MYSQL Full GROUP BY

时间:2019-06-28 13:49:07

标签: mysql sql database query-optimization mysql-5.7

我正在研究一个查询,该查询必须尽可能通用才能重用。 查询涉及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;

我可以通过禁用ONLY_FULL_GROUP_BY模式在MySQL v5.7及更高版本中运行上述查询。 当我这样做时,查询结果会有所不同。

  

MySQL <5.7结果为 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行

数据库小提琴

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 :(得分:0)

这似乎可以满足您的要求:

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;

答案 1 :(得分:0)

运载戈登斯进一步回答:

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)

相关问题