我有一个名为"message"的简单SQLite表:
sequence INTEGER PRIMARY KEY type TEXT content TEXT
我想获取每种类型的最后一条消息的内容(由其序列决定).令我惊讶的是,以下简单查询有效:
SELECT MAX(sequence), type, content FROM message GROUP BY type
很惊讶,因为我知道MSSQL或Postgres会拒绝在SELECT列表中包含一个不属于GROUP BY子句或聚合函数的列,我必须进行连接,如下所示:
SELECT m.sequence, m.type, m.content FROM ( SELECT MAX(sequence) as sequence, type FROM message GROUP BY type ) g JOIN message m ON g.sequence = m.message_sequence
我的问题是:在SQLite中使用第一个更简单的查询形式是否安全?直觉上它选择与"MAX(序列)"值匹配的"内容"值是有道理的,但文档似乎根本没有谈到这一点.当然,如果序列不是唯一的,那么结果将是未定义的.但是,如果序列是唯一的,就像我的情况一样,这是保证还是仅仅是一个可以改变的幸运实现细节?
您可以"安全地"使用这些查询,也就是说,如果额外的列在功能上依赖于您分组的列,则不会产生不明确的结果:
SELECT c.parent_id, COUNT(*), p.any_column FROM child_table c JOIN parent_table p USING (parent_id) GROUP BY c.parent_id;
上面的例子可以在SQLite中使用,并产生一个明确的结果,因为p.any_column
每组不可能有多个值.但是,此查询严格违反SQL标准,大多数品牌的RDBMS都会引发错误.
但是,编写一个产生模糊结果的查询太容易了.为每个组命名一个具有多个值的列时,无法控制结果集中返回的值.
在实践中,MySQL返回第一行中相对于物理存储的值,SQLite返回最后一行的值.但它完全依赖于实现而且不可靠.如果任一软件的下一个版本更改其内部,则升级后可能会得到不同的查询结果.所以最好不要依赖这种行为.
关于你的例子,哪里content
应该"直观地"得到sequence
MAX 行的值.但这真的很直观吗?考虑以下其他情况:
SELECT MAX(sequence), MIN(sequence), type, content FROM message GROUP BY type
那么哪一行现在提供的价值content
?哪一行sequence
是MAX,sequence
哪一行是MIN?
如果您使用非唯一列(例如date
),并且有多个行具有相同的MAX值date
,但是不同的值,该content
怎么办?
SELECT MAX(date), type, content FROM message GROUP BY type
什么样的其他聚合函数AVG()
或SUM()
?可能是聚合的值对应于表中没有单独的行.那么现在哪一行应该提供的价值content
?
SELECT AVG(sequence), type, content FROM message GROUP BY type