WHERE子句的顺序影响结果

问题描述:

我有一个奇怪的问题,一个selectWHERE条款中的订单可能会影响结果吗?WHERE子句的顺序影响结果

这是我的选择:当我使用这个条件 http://dl.dropbox.com/u/4892450/sqlSelectProblem/select1.PNG

 
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 

这将重现这一结果

where g.uuid = 'abcdefghijklmnopqrstuvwz' and c.uuid = 'HMUUcabR1S4GRTIwt3wWxzCO' (顺序不同),我得到不同的结果(参见errorId栏): http://dl.dropbox.com/u/4892450/sqlSelectProblem/select2.PNG

你能帮我吗?整个选择是错误的,还是可能是一个mysql错误?

+1

因此,这两个屏幕大小的唯一区别就是一个是“9”而另一个是“NULL”的errorID? – 2013-03-04 15:27:25

+0

也许你的基础数据在两个查询之间改变。 where子句中的顺序不会影响结果。 – 2013-03-04 15:28:15

+3

也许这是由于你在'SELECT'中有多个列,它们不在'GROUP BY'中。虽然MySQL允许(其他RDBMS不会),但它通常会导致非分组列的意外行为(不确定结果)。 – 2013-03-04 15:28:23

结果之间的唯一区别是errorId列。 sql标准(sql-92标准,检出the link)不允许使用未分组和未分类的列,甚至不会在大多数数据库引擎中运行。所以,在这种情况下引擎的行为没有规定。 Accoding到docs(感谢Marcus Adams):

的MySQL扩展了,这样的选择列表可参考在GROUP不BY子句中命名非聚合列使用GROUP的。这意味着前面的查询在MySQL中是合法的。您可以使用此功能通过避免不必要的列排序和分组来获得更好的性能。但是,这非常有用,因为每个未在GROUP BY中命名的非聚合列中的所有值对于每个组都是相同的。服务器可以*选择每个组中的任何值,因此除非它们相同,否则所选值是不确定的。在GROUP BY列表

MAX(e.id) as errorId 

或包括它:

你可以得到errorId为总价值

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

不是故意随机的,就像“不确定”一样。通常每组需要第一个,但这不能保证。 – 2013-03-04 15:30:28

+0

@MichaelBerkowski谢谢,我已经更新了我的答案。 – 2013-03-04 15:36:44

+1

虽然你的回答对于这个问题是正确的,但是sql标准**不允许声明**未分组和未聚合的列。虽然这在我知道的任何DBMS中都没有完全实现,但该标准指出可以包含功能上依赖于组中包含的列的列。例如。通过主键分组将允许您引用该表中的任何列。 – GarethD 2013-03-04 15:42:26

你已经在你的代码有两个不同的连接树,主要有:

   user 
      / \ 
    group_user  build 
    /   \ 
    group    module 
     |    | 
    course   error 

这样的结构导致不确定的结果,特别是如果的结果中加入一个分支有与其他分支不同的匹配记录数量。 MySQL必须尝试填写缺失的位,并猜测。更改WHERE子句的顺序可以并将改变整个结果,因为你正在改变mysql猜测的方式。

按聚合前的所有列进行分组。最佳实践...大多数情况下。并可能很可能扭曲你的答案...