在SQLite中,如果我这样做:
CREATE TABLE fraction (
id Int,
tag Int,
num Int,
den Int,
PRIMARY KEY (id)
);
INSERT INTO fraction VALUES (1,1,3,4);
INSERT INTO fraction VALUES (2,1,5,6);
INSERT INTO fraction VALUES (3,2,3,8);
INSERT INTO fraction VALUES (4,2,5,7);
INSERT INTO fraction VALUES (5,1,10,13);
INSERT INTO fraction VALUES (6,2,5,7);
SELECT fraction.tag, max(1.0 * fraction.num / fraction.den)
FROM fraction
GROUP BY fraction.tag;
我会得到结果:
1|0.833333333333333
2|0.714285714285714
然后,如果我发出:
SELECT fraction.tag, max(1.0 * fraction.num / fraction.den),
fraction.num, fraction.den
FROM fraction
GROUP BY fraction.tag;
我会得到结果:
1|0.833333333333333|5|6
2|0.714285714285714|5|7
后者是我所期待的,但它似乎比任何可预测或可靠的事故更幸福。例如,如果汇总函数sum
而不是min
,某些类型的“rider”列就没有意义了。
在我正在做的一个当前项目中,我正在使用一个连接自己的表来模拟后者:
SELECT DISTINCT fraction_a.tag, fraction_a.high,
fraction_b.num, fraction_b.den
FROM
(SELECT fraction.tag, max(1.0 * fraction.num / fraction.den) AS high
FROM fraction
GROUP BY fraction.tag)
AS fraction_a JOIN
(SELECT fraction.tag, fraction.num, fraction.den
FROM fraction)
AS fraction_b
ON fraction_a.tag = fraction_b.tag
AND fraction_a.high = 1.0 * fraction_b.num / fraction_b.den;
产生
1|0.833333333333333|5|6
2|0.714285714285714|5|7
但我发现这种语法难看,不切实际且难以维护。
由于我将在几种SQL方言之间移植我的项目,我需要一种在所有方言中都可靠的解决方案。所以,如果我必须咬紧牙关并使用我将要的丑陋语法,但我更喜欢使用更清洁的语法。
答案 0 :(得分:1)
在SELECT
子句中包含未出现在GROUP BY
子句中的非聚合列是不可移植的,可能会导致错误/意外结果。您使用的语法不是 cleaner - 这是完全错误的,并且恰好在SQLite上工作。它不适用于Oracle(导致语法错误),它在MySQL上不会按预期工作(它将从组中返回随机值),并且它可能不适用于其他RDBMS。
实现这一目标最直接的方法是使用窗口函数 - 但由于你需要支持SQLite,这是不可能的。
请注意,如果您碰巧有几个最大值,那么您的第二种方法(“丑陋”查询)将为每个标记返回多行。这可能是也可能不是你想要的。
所以咬紧牙关并使用类似你的丑陋方法 - 它是可移植的并且可以按预期工作。
答案 1 :(得分:0)
当您使用GROUP BY时,数据库必须从(可能)多个输入行创建单个输出行。
GROUP BY子句中提到的列对于组中的所有行具有相同的值,因此这是要使用的输出值。
具有一些聚合函数的列使用它来计算输出值。
但是,其他列是个问题,因为组中可能存在不同的值。 SQL标准禁止这样做。 MySQL忘记检查此错误,并为输出提供一些随机行的值。 SQLite允许这与MySQL兼容。
从版本3.7.11开始,当您使用MIN或MAX时,SQLite会保证其他列来自具有最小/最大值的记录。