首页 文章

WHERE子句的顺序正在影响结果

提问于
浏览
1

我有一个奇怪的问题,一个 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 错误?

3 回答

  • 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
    

    然后您的查询结果应该是稳定的 .

    Further reading:

    Why does MySQL add a feature that conflicts with SQL standards? - sql标准和mysql实现之间差异的详细解释 . (感谢GarethD

  • 0

    你的代码中有两个不同的JOIN树,主要是:

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

    这样的构造导致未定义的结果,特别是如果一个分支中的连接结果具有与另一个分支中不同数量的匹配记录 . MySQL必须尝试填写缺失的位,并猜测 . 更改 WHERE 子句的顺序可以并且将更改完整结果,因为您正在改变mysql猜测的方式 .

  • 1

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

相关问题