mysql`order by`结果不正确

时间:2017-01-20 13:41:25

标签: mysql

我有一个看起来像的mysql查询:

(SELECT datum AS dt, dat1, dat2, num FROM maanden WHERE DATE_FORMAT(datum, '%Y') >= DATE_FORMAT(NOW() - INTERVAL 2 YEAR, '%Y') AND DATE_FORMAT(datum, '%Y') < DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y') ORDER BY datum ASC)
UNION
(SELECT datum AS dt, dat1, dat2, num FROM maanden WHERE DATE_FORMAT(datum, '%Y') >= DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y') AND DATE_FORMAT(datum, '%Y') < DATE_FORMAT(NOW(), '%Y') ORDER BY datum ASC);

结果:

+---------------------+------+------+-----+
| dt                  | dat1 | dat2 | num |
+---------------------+------+------+-----+
| 2015-01-01 00:00:00 |  165 |    0 | 127 |
| 2015-02-01 00:00:00 |  101 |    0 |  81 |
| 2015-03-01 00:00:00 |  120 |    0 | 124 |
| 2015-04-01 00:00:00 |  106 |    0 |  49 |
| 2015-05-01 00:00:00 |  101 |    0 |  20 |
| 2015-06-01 00:00:00 |  117 |    0 |  19 |
| 2015-07-01 00:00:00 |  136 |    0 |  17 |
| 2015-08-01 00:00:00 |  184 |    0 |   8 |
| 2015-09-01 00:00:00 |  117 |    0 |  20 |
| 2015-10-01 00:00:00 |  173 |    0 |  59 |
| 2015-11-01 00:00:00 |  169 |    0 |  74 |
| 2015-12-01 00:00:00 |  257 |    0 | 108 |
| 2016-02-01 00:00:00 |  217 |    0 | 151 |
| 2016-03-01 00:00:00 |  123 |    0 |  72 |
| 2016-04-01 00:00:00 |  145 |    0 |  44 |
| 2016-05-01 00:00:00 |  169 |    0 |  30 |
| 2016-06-01 00:00:00 |   92 |    0 |   7 |
| 2016-07-01 00:00:00 |  143 |    0 |   9 |
| 2016-08-01 00:00:00 |  155 |    0 |   9 |
| 2016-09-01 00:00:00 |  150 |    0 |  11 |
| 2016-10-01 00:00:00 |  162 |    0 |  64 |
| 2016-11-01 00:00:00 |  170 |    0 | 113 |
| 2016-12-01 00:00:00 |  243 |    0 | 124 |
| 2016-01-01 00:00:00 |  190 |    0 | 123 |
+---------------------+------+------+-----+
24 rows in set (0.04 sec)

为什么2016-01-01 00:00:00是最后一行?如果我只去年(没有UNION):

(SELECT datum AS dt, dat1, dat2, num FROM maanden WHERE DATE_FORMAT(datum, '%Y') >= DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y') AND DATE_FORMAT(datum, '%Y') < DATE_FORMAT(NOW(), '%Y') ORDER BY datum ASC);

我得到了正确的结果,是:

+---------------------+------+------+-----+
| dt                  | dat1 | dat2 | num |
+---------------------+------+------+-----+
| 2016-01-01 00:00:00 |  190 |    0 | 123 |
| 2016-02-01 00:00:00 |  217 |    0 | 151 |
| 2016-03-01 00:00:00 |  123 |    0 |  72 |
| 2016-04-01 00:00:00 |  145 |    0 |  44 |
| 2016-05-01 00:00:00 |  169 |    0 |  30 |
| 2016-06-01 00:00:00 |   92 |    0 |   7 |
| 2016-07-01 00:00:00 |  143 |    0 |   9 |
| 2016-08-01 00:00:00 |  155 |    0 |   9 |
| 2016-09-01 00:00:00 |  150 |    0 |  11 |
| 2016-10-01 00:00:00 |  162 |    0 |  64 |
| 2016-11-01 00:00:00 |  170 |    0 | 113 |
| 2016-12-01 00:00:00 |  243 |    0 | 124 |
+---------------------+------+------+-----+
12 rows in set (0.01 sec)

尝试使用()并且没有()的最后一个查询,但没有区别。任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:1)

每个查询的顺序都是开销。您需要按整个联合集进行排序。否则,每个订单仅适用于单个查询。

由于没有为整个联盟指定顺序,引擎可以按任何定义的顺序返回结果,它恰好是2016-12-01最后一次。

SELECT * 
FROM (SELECT datum AS dt, dat1, dat2, num 
      FROM maanden 
      WHERE DATE_FORMAT(datum, '%Y') >= DATE_FORMAT(NOW() - INTERVAL 2 YEAR, '%Y')   
        AND DATE_FORMAT(datum, '%Y') < DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y') 
      UNION 
      SELECT datum AS dt, dat1, dat2, num 
      FROM maanden 
      WHERE DATE_FORMAT(datum, '%Y') >= DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y') 
        AND DATE_FORMAT(datum, '%Y') < DATE_FORMAT(NOW(), '%Y')
     ) 
ORDER BY datum ASC;

答案 1 :(得分:1)

您的查询按设计工作。行为在documentation of the UNION SQL statement

中指定
  

对单个ORDER BY语句使用SELECT表示行在最终结果中的显示顺序,因为默认情况下UNION会生成一组无序行。因此,在此上下文中使用ORDER BY通常与LIMIT结合使用,因此它用于确定要为SELECT检索的所选行的子集,即使它不一定会影响最终UNION结果中这些行的顺序。如果ORDER BYLIMIT出现SELECT,则会对其进行优化,因为它无论如何都无效。

     

要使用ORDER BYLIMIT子句对整个UNION结果进行排序或限制,请为各个SELECT语句添加括号并放置ORDER BY或{ {1}}在最后一个之后。

因此,执行您的预期的查询是:

LIMIT

作为旁注,您可以使用YEAR()函数代替( SELECT datum AS dt, dat1, dat2, num FROM maanden WHERE DATE_FORMAT(datum, '%Y') >= DATE_FORMAT(NOW() - INTERVAL 2 YEAR, '%Y') AND DATE_FORMAT(datum, '%Y') < DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y') ) UNION ( SELECT datum AS dt, dat1, dat2, num FROM maanden WHERE DATE_FORMAT(datum, '%Y') >= DATE_FORMAT(NOW() - INTERVAL 1 YEAR, '%Y') AND DATE_FORMAT(datum, '%Y') < DATE_FORMAT(NOW(), '%Y') ) ORDER BY datum ASC 来简化查询(并提高其速度)。通过预先计算您想要比较的年份的第一天和最后一天(或日期时间),然后将DATE_FORMAT()与它们进行比较,可以进一步提高其速度。