Обходной путь для MYSQL Full GROUP BY - PullRequest
2 голосов
/ 28 июня 2019

Я работаю над запросом, который должен быть максимально универсальным для повторного использования. Запрос включает в себя GROUP BY.

Однако я не могу указать столбцы, так как мне нужно, чтобы они были универсальными.

Цель запроса:

  • Назначает ключ времени каждой строке, используя столбец даты.
  • Затем я использую GROUP BY, чтобы получить только несколько значений группы.
  • По сути, я хочу уменьшить количество очков в данный день.
  • Таким образом, если в день, скажем, 4 очка, я использую GROUP BY, чтобы уменьшить его до 2 очков в день, а затем выбрать то же самое, скажем, в новый дБ.

Запрос

SELECT * FROM
   (SELECT h.* FROM testdb h
   WHERE h.date <= '2016-01-02 23:30:00'
   GROUP BY FLOOR(UNIX_TIMESTAMP(h.date)/((1440/2)*60))
   UNION
   SELECT c.* FROM testdb c
   WHERE c.date> '2016-01-02 23:30:00') m;

Я могу выполнить вышеуказанный запрос в MySQL v5.7 и выше, отключив режим ONLY_FULL_GROUP_BY. Когда я это делаю, результат запроса меняется.

MySQL <5.7: <strong>17 строк .

MySQL> 5,7 (при отключенной полной группе) результат 18 строк .

Мои сомнения:

  • Почему набор результатов меняется, группа в действительности не должна изменять результат в моем случае.
  • Любой способ обойти это без необходимости отключать FULL GROUP BY?

Я читал о MySQL ANY_VALUE, но опять же он не работает с SELECT ANY_VALUE(*)

Нужна помощь о том, как этого добиться :) Спасибо

Обновление 1

Локальный компьютер:

Версия SQL 5.7.24

Режим SQL:

STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION

Запрос в вопросе:

   SELECT * FROM
   (SELECT h.* FROM testdb h
   WHERE h.date <= '2016-01-02 23:30:00'
   GROUP BY FLOOR(UNIX_TIMESTAMP(h.date)/((1440/2)*60))
   UNION
   SELECT c.* FROM testdb c
   WHERE c.date> '2016-01-02 23:30:00') m;

Шаги, чтобы повторить проблему:

CREATE TABLE testdb ( id int primary key auto_increment,date timestamp);


    INSERT INTO testdb (date) VALUES ('2015-12-31 00:00:00');
    INSERT INTO testdb (date) VALUES ('2015-12-31 06:00:00'); 
    INSERT INTO testdb (date) VALUES ('2015-12-31 18:00:00');
    INSERT INTO testdb (date) VALUES ('2016-01-01 00:00:00');
    INSERT INTO testdb (date) VALUES ('2016-01-01 06:00:00');
    INSERT INTO testdb (date) VALUES ('2016-01-01 18:00:00');
    INSERT INTO testdb (date) VALUES ('2016-01-02 00:00:00'); 
    INSERT INTO testdb (date) VALUES ('2016-01-02 06:00:00'); 
    INSERT INTO testdb (date) VALUES ('2016-01-02 18:00:00'); 
    INSERT INTO testdb (date) VALUES ('2016-12-31 00:00:00'); 
    INSERT INTO testdb (date) VALUES ('2016-12-31 06:00:00'); 
    INSERT INTO testdb (date) VALUES ('2016-12-31 06:01:00'); 
    INSERT INTO testdb (date) VALUES ('2016-12-31 12:00:00'); 
    INSERT INTO testdb (date) VALUES ('2016-12-31 18:00:00'); 
    INSERT INTO testdb (date) VALUES ('2017-01-01 00:00:00'); 
    INSERT INTO testdb (date) VALUES ('2017-01-01 06:00:00');
    INSERT INTO testdb (date) VALUES ('2017-01-01 18:00:00');
    INSERT INTO testdb (date) VALUES ('2017-01-02 00:00:01'); 
    INSERT INTO testdb (date) VALUES ('2017-01-02 06:00:00'); 
    INSERT INTO testdb (date) VALUES ('2017-01-02 18:00:00');

Результат запроса:

18 строк

DB Fiddle

https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=6082783c8a2c8ab1aa5cb5849bfcb06f

Версия SQL 5.7.26

РЕЖИМ SQL

STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION

Результат запроса:

17 строк

Ответы [ 2 ]

0 голосов
/ 28 июня 2019

Несущие Гордоны. Ответьте дальше:

SELECT  ( SELECT COUNT(DISTINCT FLOOR(UNIX_TIMESTAMP(date)/((1440/2)*60)))
                          FROM testdb WHERE date <= '2016-01-02 23:30:00' )
      + ( SELECT COUNT(*) FROM testdb WHERE date >  '2016-01-02 23:30:00');

То есть не надо извлекать какие-либо значения, так как вам, кажется, нужно только количество.

(Если вам нужны значения, то , которые id и т. Д., Вы хотите ??)

Эта формулировка будет работать быстрее, чем любая из других обсуждаемых, особенно если у вас есть INDEX(date).

0 голосов
/ 28 июня 2019

Казалось бы, это делает то, что вы хотите:

SELECT COUNT(*)
FROM (SELECT FLOOR(UNIX_TIMESTAMP(h.date)/((1440/2)*60)) FROM testdb h
      WHERE h.date <= '2016-01-02 23:30:00'
      GROUP BY FLOOR(UNIX_TIMESTAMP(h.date)/((1440/2)*60))
      UNION
      SELECT c.date
      FROM testdb c
      WHERE c.date> '2016-01-02 23:30:00'
     ) m;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...