2

我有一个奇怪的问题selectWHERE子句中的顺序是否可能会影响结果?

这是我的选择:

选择 u.userName, u.fullName, g.uuid 作为 groupUuid, g.name 作为 `group`,
    m.number 作为模块,count(distinct b.uuid) 作为 buildCount,max(b.datetime),
    count(distinct e.buildId) as errorBuildCount, e.id as errorId
    来自用户 u
    在 GU.user_id = u.id 上内部加入 GROUP_USER GU
    在 g.id = GU.group_id 上内部加入 `Group` g
    在 c.id = g.courseId 上内部加入课程 c
    左外连接 Build b on b.userId = u.id
    在 m.id = b.moduleId 上左外连接模块 m
    e.buildId = b.id 上的左外连接错误 e
    其中c.uuid = 'HMUUcabR1S4GRTIwt3wWxzCO' 和 g.uuid = 'abcdefghijklmnopqrstuvwz'
    按 u.userName、m.number、c.uuid、g.uuid 分组
    按 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错误?

4

3 回答 3

3

结果之间的唯一区别是errorId列。sql 标准(sql-92 标准,查看链接)不允许未分组和未聚合的列,甚至不会在大多数数据库引擎中运行。因此,未指定引擎在这种情况下的行为。根据文档(感谢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

那么你的查询结果应该是稳定的。

进一步阅读:

为什么 MySQL 会添加一个与 SQL 标准相冲突的特性?- 详细解释 sql 标准和 mysql 实现之间的差异。(感谢GarethD

于 2013-03-04T15:29:06.377 回答
1

您的代码中有两个不同的 JOIN 树,本质上是:

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

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

于 2013-03-04T15:30:41.167 回答
0

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

于 2013-03-04T15:31:57.850 回答