我发现有时,我的结果使用以下SQL(MySQL)查询错误地排序:
SELECT u.id, u.firstName, u.lastName, u.email, u.ssoProfile, u.vip, SUM(p.number) AS totalPoints
FROM (
SELECT u.id FROM user u
ORDER BY u.firstName ASC, u.lastName ASC, u.email ASC
LIMIT 100, 10
) u2
INNER JOIN `user` u
ON u2.id = u.id
LEFT JOIN `point` p
ON u.id = p.user
AND p.expiryDate > NOW()
GROUP BY u.id
正如您所看到的,我在子查询中按用户排序。但是,我注意到有时候很少会得到不符合指定顺序的结果。我想我需要在外部查询上订购?但我想了解这个查询的错误。为什么我的用户订单搞砸了?
更新
我在外部查询中添加了一个订单。令人惊讶的是,我发现我的结果仍然可以按错误的顺序返回
SELECT u.id, u.firstName, u.lastName, u.email, u.ssoProfile, u.vip, SUM(p.number) AS totalPoints
FROM (
SELECT u.id FROM user u
ORDER BY u.firstName ASC, u.lastName ASC, u.email ASC
LIMIT 100, 10
) u2
INNER JOIN `user` u
ON u2.id = u.id
LEFT JOIN `point` p
ON u.id = p.user
AND p.expiryDate > NOW()
GROUP BY u.id
ORDER BY u.firstName ASC, u.lastName ASC, u.email ASC
结果如下:
[ { id: 4834, firstName: 'F01', lastName: 'L01' },
{ id: 4835, firstName: 'F00', lastName: 'L00' }, // << notice F00 is after F01?
{ id: 4836, firstName: 'F02', lastName: 'L02' },
{ id: 4837, firstName: 'F03', lastName: 'L03' },
{ id: 4838, firstName: 'F04', lastName: 'L04' },
{ id: 4839, firstName: 'F05', lastName: 'L05' },
{ id: 4840, firstName: 'F06', lastName: 'L06' },
{ id: 4841, firstName: 'F07', lastName: 'L07' },
{ id: 4842, firstName: 'F08', lastName: 'L08' },
{ id: 4843, firstName: 'F09', lastName: 'L09' } ]
@ lad2025提到它可能是因为我在评论中错误地使用了GROUP BY。但是,我检查了ID匹配。例如,F00确实属于用户ID 4835。
答案 0 :(得分:1)
首先,@ lad2025和@Tim Biegeleisen都给出了正确的评论。
查询优化器更改查询,以使结果集保持不变,并且时间保持尽可能低。
查询优化器会更改命令的顺序,例如JOINs
和WHERE
条件。
这些链接可以为您提供有关查询优化如何工作的有用信息(link1和link2)。
在MySQL中,您可以使用EXPLAIN命令查看在查询优化更改后如何执行实际查询。
关于解决您的问题,您只需在外部查询中复制ORDER BY
,因为这样您就可以告诉RDBMS您也希望对结果进行排序。
我怀疑是在查询重新排序(看看这个 - &gt; heuristic optimisation)改变了一些东西,因为你在子查询中有与外部查询相同的表(不是最准确的解释,我知道)。 这很难确定,因为它取决于您所拥有的索引,执行时的内存大小,表的大小等等。
您的查询应如下所示:
SELECT u.id, u.firstName, u.lastName, u.email, u.ssoProfile, u.vip, SUM(p.number) AS totalPoints
FROM (
SELECT u.id FROM user u
ORDER BY u.firstName ASC, u.lastName ASC, u.email ASC
LIMIT 100, 10
) u2
INNER JOIN `user` u
ON u2.id = u.id
LEFT JOIN `point` p
ON u.id = p.user
AND p.expiryDate > NOW()
GROUP BY u.id
ORDER BY u.firstName ASC, u.lastName ASC, u.email ASC
我要添加的一个注意事项是,您应该仍然在子查询中保留ORDER BY
,因为LIMIT
条件会在ORDER BY
之后执行,因此您最终会遇到不同的情况结果与原始查询进行比较。
答案 1 :(得分:0)
您已经获得了正确答案。您需要ORDER BY来保证订购结果。子查询中的订单不一定会影响结果的顺序。所以解决方案是添加
ORDER BY u.firstName, u.lastName, u.email
在您的查询结束时。
由于您仍然以错误的顺序获取数据,因此必须是其他错误。
最有可能的是查询为您提供了正确排序的数据,但此订单稍后会更改。所以也许你可以在一个应用程序中显示这个,可能是在重新排序记录的列表框等中。直接使用您的DBMS检查您的查询,看看您是否正确订购了记录。
另一种可能性是您没有注意到空白或不可打印的字符,即可能是'F01'而不是'F01',这就是它在'F00'之前出现的原因。