假设您有这样的查询:
SELECT g, v
FROM t
GROUP BY g;
在这种情况下,对于g 的每个可能值,mysql 选择v 的对应值之一。
但是,选择哪一个取决于某些情况。
我在某处读到,对于每组 g,v 的第一个值被保留,按照记录插入表 t 的顺序。
这很丑陋,因为表中的记录应该被视为一个 set,其中元素的顺序无关紧要。这太“mysql-ish”了……
如果您想确定要保留 v 的哪个值,您需要像这样为 t 应用子选择:
SELECT g, v
FROM (
SELECT *
FROM t
ORDER BY g, v DESC
) q
GROUP BY g;
通过这种方式,您可以定义外部查询处理子查询记录的顺序,因此您可以相信它将为g 的各个值选择v 的哪个值。
但是,如果您需要一些 WHERE 条件,则要非常小心。如果您将 WHERE 条件添加到子查询,那么它将保持该行为,它将始终返回您期望的值:
SELECT g, v
FROM (
SELECT *
FROM t
WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
GROUP BY g;
这是您所期望的,子选择过滤器并对表格进行排序。它保留g 具有给定值的记录,外部查询返回g 和v 的第一个值。
但是,如果您将相同的 WHERE 条件添加到外部查询,那么您会得到一个不确定的结果:
SELECT g, v
FROM (
SELECT *
FROM t
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g;
令人惊讶的是,当您一次又一次地执行相同的查询时,您可能会得到 v 的不同值,这很奇怪。预期的行为是以适当的顺序从子查询中获取所有记录,在外部查询中过滤它们,然后选择与前面示例中选择的相同的记录。但事实并非如此。
它看似随机地为v 选择一个值。如果我执行更多 (~20) 次但分布不均匀,则相同的查询为 v 返回不同的值。
如果不添加外部 WHERE,而是指定 HAVING 条件,如下所示:
SELECT g, v
FROM (
SELECT *
FROM t1
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g
HAVING g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9';
然后您再次获得一致的行为。
结论:我建议完全不要依赖这种技术。如果您真的想要/需要避免外部查询中的 WHERE 条件。如果可以的话,在内部查询中使用它,或者在外部查询中使用 HAVING 子句。
我用这些数据对其进行了测试:
CREATE TABLE t1 (
v INT,
g VARCHAR(36)
);
INSERT INTO t1 VALUES (1, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');
INSERT INTO t1 VALUES (2, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');
在 mysql 5.6.41 中。
也许这只是一个在较新版本中得到/修复的错误,如果您有使用较新版本的经验,请提供反馈。