1

I am running MySQL 14.14 Distrib 5.7.40 for Linux (x86_64) on my BlueHost VPS. A few months ago I could run this command successfully:

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

I have to go rerun this every few months to avoid this error:

...this is incompatible with sql_mode=only_full_group_by

Today when I ran that it appeared successful, but the SQL errors remain in my web app:

Invalid query: Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'MyDatabase.s.EventDate' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

My full query that is breaking:

SELECT g.GroupID,
       g.GroupName,
       count(s.EventDate) AS Total
FROM Groups g
LEFT JOIN Schedule s ON g.GroupID = s.GroupID
JOIN Settings se ON g.GroupID = se.GroupID
WHERE g.OrganizationID = 479
AND g.IsActive = 1
AND IFNULL(g.IsDeleted, 0) = 0
AND IFNULL(g.IsHidden, 0) = 0
AND se.SettingName = 'HideGroupNoGames'
AND (s.EventDate > DATE_ADD(NOW(), INTERVAL 0 HOUR)
    OR g.CreateDate > DATE_ADD(DATE_ADD(NOW(), INTERVAL -1 DAY), INTERVAL 0 HOUR)
    OR se.SettingValue = 'False')
GROUP BY g.GroupID, g.GroupName
ORDER BY s.EventDate, g.GroupName

And when I run SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));, the error doesn't go away.

I tried stopping and starting the mysqld service from terminal. Success, but SQL error remains.

When I run this: select @@sql_mode;, it still displays this:

ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Even though I already ran this:

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

...and this:

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;

I would love to fix the SQL statement so the error goes away, but I don't know how. Whenever I tweak it I get different and incorrect results.

I learned from this SO post that SET GLOBAL is temporary and will reset when mysql restarts. But when I run cat my.cnf, I don't even see the sql_mode:

[mysqld]
performance-schema=0

default-storage-engine=MyISAM
interactive_timeout=300
key_cache_block_size=4096
max_heap_table_size=32M
max_join_size=1000000000
max_allowed_packet=268435456
open_files_limit=40000
query_cache_size=32M
thread_cache_size=100
tmp_table_size=32M
wait_timeout=7800
max_user_connections=50
myisam_recover_options=FORCE
innodb_file_per_table=1
innodb_flush_log_at_trx_commit=0
innodb_purge_threads=1
innodb_support_xa=0
innodb_thread_concurrency=8
pid-file=/var/lib/mysql/mysqld.pid
innodb_buffer_pool_size=55574528

I think perhaps any of the following solutions would work for me:

  • Why doesn't SET GLOBAL sql_mode work any more, and how can I make it work?
  • Why doesn't my.cnf contain anything about sql_mode?
  • How can I fix my query so the SQL mode doesn't matter, and doesn't error?
halfer
  • 19,824
  • 17
  • 99
  • 186
HerrimanCoder
  • 6,835
  • 24
  • 78
  • 158
  • If you don't see the `sql_mode` in `my.cnf`, it uses the default, which contains `ONLY_FULL_GROUP_BY`. You need to add it to my.cnf. – Barmar Oct 12 '22 at 22:43
  • 1
    Strict sql mode also contains only full group by sql mode, hence the error message you see. However your whole approach is absolutely wrong! You should fix your sql queries to comply with the sql standard, rather than enabling mysql to allow such queries to run. To fix your query: remove eventdate from the order by clause, as it makes absolutely no sense logically to be there as you are not retrieving that column in the resultset and that details is aggregated up using the count() function. – Shadow Oct 12 '22 at 22:54
  • edit your question to show (as text, not images) output of `select version();` and (both before and after doing the `SET GLOBAL sql_mode...`) `select @@sql_mode;`. does your query succeed immediately after the SET GLOBAL? (note that that setting will only last until the service restarts; for a permanent change, you must set it in a config file (to the *result* of the REPLACE; you can't use REPLACE in the config file) – ysth Oct 12 '22 at 23:26
  • are you running things from the command line client or some other client that will inform you of errors? at least one of the commands you show is missing an end quote. – ysth Oct 12 '22 at 23:32
  • as far as fixing your query, you are trying to sort by s.EventDate but there is potentially more than one value per grouping so it will be using an arbitrary one of those to sort on when you suppress the error. to fix it, sort on min(s.EventDate) or max(s.EventDate) or something else that is determinate for a given grouping. – ysth Oct 12 '22 at 23:35
  • @Shadow sorting by date does indeed make sense, but they need to decide which date of the grouping to order by – ysth Oct 12 '22 at 23:37
  • if you do not set sql mode in the config file, each version of mysql will have a default value (that changes from version to version) – ysth Oct 12 '22 at 23:39
  • @Shadow what do you mean by "Strict sql mode also contains only full group by sql mode"? STRICT_TRANS_TABLES? that does *not* contain only full group by. – ysth Oct 12 '22 at 23:48
  • Also see [Why should not disable ONLY_FULL_GROUP_BY](https://stackoverflow.com/questions/64824498/why-should-not-disable-only-full-group-by/64831540#64831540) – danblack Oct 13 '22 at 01:44
  • Thanks everyone. I fixed my sql, and I understand all this better now. And yes, I do have a reason to sort by DATE even though it's not in the SELECT. – HerrimanCoder Oct 13 '22 at 14:58
  • Did you try adding sql_mode to my.cnf or one of the files it 'includes'? – Rick James Oct 14 '22 at 00:43
  • How much RAM do you have? Do you use MyISAM? Or InnoDB? – Rick James Oct 14 '22 at 00:44
  • "Why doesn't my.cnf contain anything about sql_mode?" -- There are several hundred settings that can be added to that file! – Rick James Oct 14 '22 at 00:45

1 Answers1

3

Okay, a couple of things are going on.

  • Using SET GLOBAL doesn't affect the current session in which you ran that statement. It changes the global option, but the current session still uses session values copied from the global values when the session starts. If you start a new session after you use SET GLOBAL, it will inherit the change.

  • You can change the current session's configuration with SET SESSION sql_mode=... or simply SET sql_mode=... which is equivalent.

  • Restarting mysqld discards any changes you made with SET GLOBAL, and reverts to the options in my.cnf (or the default value compiled-in to the mysqld executable, if the option is not specified in my.cnf). Simply changing the global option is not written to my.cnf.

    In MySQL 8.0, you can use SET PERSIST to change the global value and write it to a file so it remains in effect if you restart mysqld. Read about this in more detail: https://dev.mysql.com/doc/refman/8.0/en/set-variable.html

Both of these things have been the way it worked for years. It's likely that it's working exactly as documented.

It's recommended that you should NOT change the sql mode. Your query can be changed to comply with the default sql mode.

Since EventDate is not a column in your GROUP BY clause, it may have multiple values per group. So it's undefined what happens if you ORDER BY s.EventDate, .... Which value in the group should it use to sort?

You should resolve this by sorting by a specific value in the group. For example, these would be acceptable choices:

ORDER BY MAX(s.EventDate), g.GroupName

ORDER BY MIN(s.EventDate), g.GroupName
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • 1
    Bill, thank you very much for your excellent, detailed answer. I made the sql change and all is good now. Also I understand things better. – HerrimanCoder Oct 13 '22 at 14:53