我对一个select
有一些奇怪的问题。
WHERE
子句中的顺序是否可能影响结果?
这是我的选择:
select u.userName, u.fullName, g.uuid as groupUuid, g.name as `group`, m.number as module, count(distinct b.uuid) as buildCount, max(b.datetime), count(distinct e.buildId) as errorBuildCount, e.id as errorId from User u inner join GROUP_USER GU on GU.user_id = u.id inner join `Group` g on g.id = GU.group_id inner join Course c on c.id = g.courseId left outer join Build b on b.userId = u.id left outer join Module m on m.id = b.moduleId left outer join Error e on e.buildId = b.id where c.uuid = 'HMUUcabR1S4GRTIwt3wWxzCO' and g.uuid = 'abcdefghijklmnopqrstuvwz' group by u.userName,m.number,c.uuid, g.uuid order by g.id asc, u.fullName asc, m.number asc
这会重现这个结果: http://dl.dropbox.com/u/4892450/sqlSelectProblem/select1.PNG
当我使用这个条件时:
where g.uuid = 'abcdefghijklmnopqrstuvwz' and c.uuid = 'HMUUcabR1S4GRTIwt3wWxzCO'
(不同的顺序)我得到了不同的结果(请参阅errorId
列):
http://dl.dropbox.com/u/4892450/sqlSelectProblem/select2.PNG
mysql
错误?
答案 0 :(得分:3)
结果之间的唯一区别是errorId
列。 sql标准(sql-92标准,检出the link)不允许使用未分组和未分页的列,甚至不会在大多数数据库引擎中运行。因此,没有指定引擎在这种情况下的行为。致docs(感谢Marcus Adams):
MySQL扩展了GROUP BY的使用,因此选择列表可以引用GROUP BY子句中未命名的非聚合列。这意味着前面的查询在MySQL中是合法的。您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能。但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用。服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的。
您可以将errorId
作为汇总值:
MAX(e.id) as errorId
或将其包含在GROUP BY
列表中:
group by u.userName,m.number,c.uuid, g.uuid,e.Id
然后您的查询结果应该是稳定的。
进一步阅读:
Why does MySQL add a feature that conflicts with SQL standards? - sql标准和mysql实现之间差异的详细解释。 (感谢GarethD)
答案 1 :(得分:1)
你的代码中有两个不同的JOIN树,基本上是:
user
/ \
group_user build
/ \
group module
| |
course error
这样的构造会导致未定义的结果,特别是如果一个分支中的连接结果具有与另一个分支中不同的匹配记录数。 MySQL必须尝试填写缺失的位,并猜测。更改WHERE
子句的顺序可以并且将更改完整结果,因为您正在改变mysql猜测的方式。
答案 2 :(得分:0)
在聚合之前按所有列分组。最佳实践......在大多数情况下。并且很可能会扭曲你的答案......