A Database Error Occurred Error Number: 1055 , group by substring - mysql

Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'shows.b.show_title' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
SELECT b.show_title as show_title FROM `shows` `b`
WHERE `b`.`active` = 1
GROUP BY SUBSTRING(show_title, 1, 1)
I'm naming all columns in select query so why the error?
I know the workaround of disabling ONLY_FULL_GROUP_BY from sql_mode but how do i solve the error with the query?

Q: why the error?
Consider two rows with show_title values of 'True Detective' and 'True Lies'
The expression in the GROUP BY is going to return T for both of those rows, so those rows are going to be collapsed into a single row in the resultset.
The query can return only a single value for a column in the collapsed row, and it's indeterminate/ambiguous which of the two values to return. With ONLY_FULL_GROUP_BY in sql_mode, MySQL is adhering more closely to the ANSI SQL specification; the 1055 error is behavior similar to what we observe in other relational DBMS e.g. Oracle, Microsoft SQL Server, Teradata, DB2, et al.
Q: how do i solve the error with the query?
The normative pattern is to use an aggregate function to specify which value (out of a set of possible values) to return.
For example, MAX() or MIN(). Demonstration:
SELECT SUBSTR(b.show_title,1,1) AS s1
, MAX(b.show_title) AS max_show_title
, MIN(b.show_title) AS min_show_title
FROM shows b
WHERE b.active = 1
GROUP BY SUBSTR(b.show_title,1,1)
will avoid the 1055 error, and could return e.g.
s1 max_show_title min_show_title
-- --------------- ---------------
T True Lies True Detective

Simply use these two queries and run them as query.
Your problem will be fixed asap.
No need to restart mysql
solution :
run this query :
SET sql_mode = '';
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));

Related

MySQL 5.7 - Error sql_mode=only_full_group_by

After Updating to MySQL 5.7.11 we are getting a number of errors related to the sql_mode including only_full_group_by.
Research shows we can turn this off but it would probably be better to know how to achieve the intended goal with properly structured SQL statements.
Error:
#1140 - In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'tblslideshow.slideImage'; this is incompatible with sql_mode=only_full_group_by
Query:
SELECT
tblslideshow.slideImage,
COUNT(tblslideshow.slideID) AS countVal
FROM
tblslideshow
WHERE
tblslideshow.parentID = 3424
The goal is to return a list of values but also a Count for all returned records.
What's the best way to achieve this goal without having to change the MySQL my.ini ? And why is it a Group By error is we're not even grouping? Or is Grouping part of the proper solution?
Expected Result should be:
slideImage | countVal
Image1.jpg | 3
Image2.jpg | 3
Image3.jpg | 3
Edit: Since we are using PHP and MySQLi it may be wiser to exclude the Count() and just use "mysqli_num_rows"
When you use Aggregate function, you need to add non-aggregate columns on Group by clause.
SELECT
tblslideshow.slideImage,
COUNT(tblslideshow.slideID) AS countVal
FROM
tblslideshow
WHERE
tblslideshow.parentID = 3424
Group by tblslideshow.slideImage
EDIT
You can try to use subquery on select
SELECT t.slideImage,
(
SELECT
COUNT(tblslideshow.slideID) AS countVal
FROM
tblslideshow
WHERE
tblslideshow.parentID = 3424
) countVal
FROM tblslideshow t
WHERE t.parentID = 3424
What you are looking for is COUNT OVER, available as of MySQL 8.0:
SELECT
tblslideshow.slideImage,
COUNT(*) OVER () AS countVal
FROM
tblslideshow
WHERE
tblslideshow.parentID = 3424;
This keeps the single rows and adds the aggregate value to them.

MYSQL, GROUP BY clause; this is incompatible with sql_mode=only_full_group_by [duplicate]

This question already has answers here:
Error related to only_full_group_by when executing a query in MySql
(18 answers)
Closed 5 years ago.
The following CodeIgniter query gives an error telling;
Expression #22 of SELECT list is not in GROUP BY clause and contains
nonaggregated column 'hw3.1.hw_homework.id' which is not functionally
dependent on columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by
SELECT *, `studentid`, COUNT(studentid),
`be_user_profiles`.`first_name`, `be_user_profiles`.`last_name`
FROM `be_user_profiles`
JOIN `be_users` ON `be_users`.`id`=`be_user_profiles`.`user_id`
JOIN `hw_homework` ON `be_user_profiles`.`user_id`=`hw_homework`.`studentid`
WHERE `be_user_profiles`.`advisor` = '20'
AND `hw_homework`.`date` < '2018-06-15 00:00:00'
AND `hw_homework`.`date` > '2017-08-24 00:00:00'
AND `active` = 1
GROUP BY `be_user_profiles`.`user_id`
ORDER BY COUNT(studentid) DESC
Filename: modules/organization/models/Mhomework.php
Line Number: 226
$this->db->select('*,studentid,COUNT(studentid),be_user_profiles.first_name,be_user_profiles.last_name');
$this->db->from('be_user_profiles');
$this->db->join('be_users','be_users.id=be_user_profiles.user_id');
$this->db->join('hw_homework','be_user_profiles.user_id=hw_homework.studentid');
$this->db->where('be_user_profiles.advisor',$id);
$this->db->where('hw_homework.date <',$to);
$this->db->where('hw_homework.date >',$from);
$this->db->where('active',1);
$this->db->group_by('be_user_profiles.user_id');
$this->db->order_by('COUNT(studentid)','DESC');
$query = $this->db->get();
I removed studentid or added group_by studentid etc but none of them worked.
I know that I can set global SQL mode but I think it is not a solution for me.
mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
I want to fix the code not the way around.
In standard SQL it's very difficult to use SELECT * in a query with GROUP BY. Why? Standard SQL requires SELECTEed columns to also appear in the GROUP BY clause, with a few exceptions for columns with values that are functionally dependent on ones mentioned in the GROUP BY.
To write an aggregate query it's easiest to enumerate the columns you want in your SELECT and again in your GROUP BY. MySQL's notorious nonstandard extension to GROUP BY lets you ask for columns that aren't mentioned in the GROUP BY clause, and proceeds to return some unpredictable value for those columns.
To fix this "right" as opposed to hack around it, you need to get rid of the *. Change
$this->db->select('*,studentid,COUNT(studentid),be_user_profiles.first_name,be_user_profiles.last_name');
to
$this->db->select('studentid,COUNT(studentid),be_user_profiles.first_name,be_user_profiles.last_name');
and, for best results, change
$this->db->group_by('be_user_profiles.user_id');
to
$this->db->group_by('studentid,be_user_profiles.user_id');

How to find rows in SQL that end with the same string?

I have a question similar to the one found here: How to find rows in SQL that start with the same string (similar rows)?, and this solution works in MySQL 5.6 but not 5.7.
I have a database (t) with multiple columns, the important ones being id and filepath, and what I am trying to accomplish is retrieving all the file paths which have the same last 5 characters. The following works in MySQL5.6, and the second SELECT works fine in 5.7:
SELECT id, filepath FROM t
WHERE SUBSTRING(filepath, -5) IN
(
SELECT SUBSTRING(filepath, -5)
FROM t
GROUP BY SUBSTRING(filepath, -5)
HAVING COUNT(*) > 1
)
But when I try to run it on 5.7 I get the error
Expression #1 of HAVING clause is not in GROUP BY clause and contains
nonaggregated column 't.filepath' which is not functionally dependent on
columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by
Sample data:
id filepath
1 /Desktop/file1.txt
2 /Desktop/file2.txt
3 /Desktop/file1.txt
and I would want to return the rows with id 1 and 3. How can I fix this for MySQL5.7?
EDIT: Also can anybody point me in the right direction for the SQL to remove the duplicates? So I would want to remove the entry for id 3 but keep the entry for id 1 and 2.
Please read the mysql documentation on the subject GROUP BY and sql_mode only_full_group_by (like your error message says):
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
I think changing the inner query to this might fix the problem:
SELECT SUBSTRING(filepath, -5) AS fpath
FROM t
GROUP BY fpath
HAVING COUNT(fpath) > 1
Edit:
As to your question of why adding the "AS fpath" works:
Adding the alias "fpath" is just a clean way to do this. The point of ONLY_FULL_GROUP_BY is that each field you use in the SELECT, HAVING, or ORDER BY must also be in the GROUP BY.
So I added the fpath-alias for multiple reasons:
For performance: The query you wrote had SUBSTRING(filepath, -5) twice, which
is bad for performance. Mysql has to execute that SUBSTRING call twice,
while in my case it has to do it only once (per row).
To fix the group-by issue: You had COUNT() in the having, but "" was not in your GROUP BY statement (I'm not even sure whether that would be possible). You had to count "something", so since "fpath" was in your SELECT and in your GROUP BY, using that as your COUNT() would fix the problem.
I prefer not to put subqueries in an IN() predicate because MySQL tends to run the subquery many times.
You can write the query differently to put the subquery in the FROM clause as a derived table. That will make MySQL run the subquery just once.
SELECT id, filepath
FROM (
SELECT SUBSTRING(filepath, -5) AS suffix, COUNT(*) AS count
FROM t
GROUP BY suffix
HAVING count > 1
) AS t1
JOIN t AS t2 ON SUBSTRING(t2.filepath, -5) = t1.suffix
This is bound to do a table-scan though, so it's going to be a costly query. It can't use an index when doing a substring comparison like that.
To optimize this, you might create a virtual column with an index.
ALTER TABLE t
ADD COLUMN filepath_last VARCHAR(10) AS (SUBSTRING_INDEX(filepath, '/', -1)),
ADD KEY (filepath_last);
Then you can query it like this, and at least the subquery uses an index:
SELECT id, filepath
FROM (
SELECT filepath_last, COUNT(*) AS count
FROM t
GROUP BY filepath_last
HAVING count > 1
) AS t1
STRAIGHT_JOIN t AS t2 ON t2.filepath_last = t1.filepath_last
The solution that ended up working for me was found here: Disable ONLY_FULL_GROUP_BY
I ran SELECT ##sql_mode then SET ##sql_mode = followed by a string containing all the values returned by the first query except for only_full_group_by, but I'm still interested in how this is to be accomplished without changing the SQL settings.

A Database Error Occurred Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column

I have this query
SELECT substring(TGLLAHIR, 1, 7) as TGLLAHIR_,
substring(TGLLAHIR, 5, 2) as BULAN, `TGLLAHIR` as `TGL`
FROM `m_pasien`
WHERE substring(TGLLAHIR,1,4) = '2013'
GROUP BY substring(TGLLAHIR, 1, 7)
ORDER BY `TGLLAHIR` ASC
but message error showing
Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'rsukemba_kojarsuk.m_pasien.TGLLAHIR' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
How do I solve this?
You don't need group by, use distinct instead
SELECT distinct
substring(TGLLAHIR, 1, 7) as TGLLAHIR_
,substring(TGLLAHIR, 5, 2) as BULAN
,`TGLLAHIR` as `TGL`
FROM `m_pasien`
WHERE substring(TGLLAHIR,1,4) = '2013'
ORDER BY `TGLLAHIR` ASC
It seems that you are misusing the group by clause in this query. Group by is useful when aggregating data. For example, if you had a table of accounts, dates, and deposit amounts; and you wanted to know the total deposits into each account over all dates, you could write something like
select account, sum(deposits)
from some_table
group by account
It's unclear from you question alone what exactly you're trying to do, and even harder because your strangely-named variables are listed without any context. BUT! it's probably safe to say that you don't need to use a group by here, so just remove it.
P.S. I would be wary of doing a select distinct unless you know what you're throwing away and are certain that you don't need it.
You should use ANY_VALUE() aggregate function to suppress this warning message and make the query runnable. MySQL doesn't know which value of the non-aggregated field it should include in the result set. Every field that is not part of the GROUP BY clause should be wrapped in the aggregate function Here is, how it should look like:
SELECT substring(TGLLAHIR, 1, 7) as TGLLAHIR_,
substring(TGLLAHIR, 5, 2) as BULAN,
ANY_VALUE(`TGLLAHIR`) as `TGL`
FROM `m_pasien`
WHERE substring(TGLLAHIR,1,4) = '2013'
GROUP BY substring(TGLLAHIR, 1, 7)
ORDER BY `TGLLAHIR` ASC
And here is the explanation of this point in MySQL refference: https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_any-value
I think this problem due to strict mode enabled in your MySQL version. Kindly disable strict mode and try again.
To check whether strict mode is enabled or not run the below sql:
SHOW VARIABLES LIKE 'sql_mode';
If one of the value is STRICT_TRANS_TABLES, then strict mode is enabled.
To disable strict mode run the below sql:
set global sql_mode='';
Try again..

Can not Access Aliased Columns in Select Statement (MySQL)

I have a problem with Aliased Columns in MySQL!
My Query:
SELECT Price AS Pr, (Pr*10/100) FROM MyTable;
MySQL WorkBench Error: UnKnown Column 'Pr' in Field List !!!
I tested my query in W3Schools with no error !
I tested my query in W3Schools with no error!
This doesn't prove that your query is valid.
You can only use aliases in GROUP BY, ORDER BY or HAVING clauses. Your usage variant is not allowed, because the value of alias is not known when MySQL is selecting the 2-nd column.
I've got a suspicion that W3Schools uses MS Access to run user queries, and MS Access does allow such atrocity as referencing column aliases in a SELECT clause that are defined in the same SELECT clause.
The standard doesn't allow this and MySQL does follow standard in this particular case.
As for solution to your problem, I can see two options.
The more generic solution, which would run in probably any SQL product, would be to use a derived table:
SELECT
Pr,
(Pr * 10 / 100) AS SomethingElse
FROM
(
SELECT
SomeComplexExpression AS Pr
FROM MyTable
) AS sub
;
The other option would be to use a variable, which is MySQL-specific:
SELECT
#Pr := SomeComplexExpression AS Pr,
(#Pr * 10 / 100) AS SomethingElse
FROM MyTable
;
Finally, if you need to test/demonstrate if something can/cannot work in MySQL, I'd recommend using SQL Fiddle.