【问题标题】:How does implicit sorting in SELECT *,MIN(x) work in SQLite?SELECT *,MIN(x) 中的隐式排序如何在 SQLite 中工作?
【发布时间】:2016-12-11 16:08:04
【问题描述】:

今天我遇到了一个非常常见的问题,即从由group by 分割的每组数据集中选择具有最小值的行。我找到了一个 SQLite 独有的解决方案(它在 MySQL 中无法正常工作并在 PostgreSQL 中引发错误)并且不使用任何连接。它看起来像这样:

SELECT *, min(x) FROM table GROUP BY y

Here 是一个例子。

但是,我不明白 为什么 这有效 - 只是通过包含一个聚合函数,每个组都以某种方式隐式排序并返回聚合函数的结果对应的行。默认 SQL 行为是选择任意行。我翻遍了relevant SQLite documentation 并没有找到任何解释。这就是我想要解释的原因。


编辑:到目前为止,两个答案都猜测这是一个巧合。它不是。在实际表中,我使用这种方法将大约 90 条记录分成了大约 30 组,并且每条记录都按预期工作。 See for yourself.

【问题讨论】:

标签: sql sqlite


【解决方案1】:

为了与 MySQL 兼容,SQLite 允许使用既不聚合也不分组的列。

MySQL 不保证这些值来自任何特定的行,3.7.11 之前的 SQLite 也不保证。但是,由于 SQLite 中如何实现分组,在某些情况下,这些列中的值恰好来自与 min()/max() 匹配的行。

一些paying 客户发现这很有用,并希望为此提供保证,因此 SQLite enforced it in all casesdocumented it in the changelog of version 3.7.11 使其成为受支持的功能(即,它已经过测试,永远不会被删除)。

虽然可以安全使用,但此行为是 SQL 标准的违反扩展,从未正确设计过,也从未打算成为销售功能,因此在实际中未提及文档。

【讨论】:

  • 。 .你知道这种行为是否适用于多个“y”列吗?
  • 我看到了 MAX 的保证,而不是 MIN 的保证。
  • @GordonLinoff 它适用于所有列。
  • 再说一次,这不是文档所保证的。
【解决方案2】:

这可能是偶然的。 SQLite 将为每个组返回任意行。该行不一定必须具有该组的最小 x 值。

学会正确表达查询:

SELECT t.*
FROM table t
WHERE t.x = (SELECT MIN(t2.x) FROM table t2 WHERE t2.y = t.y)

【讨论】:

  • 如果有不止一行具有最小值,则此查询将无法按预期工作。如果在特定情况下这是可能的,则必须决定以某种方式在各种备选方案之间进行选择(例如,找到第二列的最小值;或主键的最小值,或者......)。跨度>
  • SQLite 似乎非常固执地总是返回小提琴示例中的“正确”行,无论我做了多少组合......所以,它看起来真的不是巧合。如果你检查这个: SELECT *, max(record_date), min(record_date) FROM mt GROUP BY id ; ...您会发现所选行是实际找到 min(record_date) 的行。如果你改变 max() 和 min() 的顺序,你会得到最大值出现的行。所以,这看起来并不是巧合。
  • @joanolo 。 . .我的猜测是id 在数据中按顺序递增,SQLite 对group by 使用稳定的排序。这些不是我在真正的查询中想要依赖的条件。
【解决方案3】:

您看到的记录是任意选择的。
你不能指望那些对你来说似乎可以解决的行为。
它可以由于表结构的变化(例如添加/删除的索引)、版本之间的变化等而改变。


https://www.sqlite.org/lang_select.html

如果 SELECT 语句是带有 GROUP BY 子句的聚合查询 ...
然后对结果集中的每个表达式进行一次评估 行组。如果表达式是一个聚合表达式,它是 对组中的所有行进行评估。否则,它被评估 针对从组内任意选择的单个行。如果 结果集中有多个非聚合表达式, 那么所有这样的表达式都会针对同一行进行评估。


这让我想起了与 Oracle 的 GROUP BY 相关的一个著名陷阱。
每个人都知道,如果您使用 GROUP BY,您可以跳过 ORDER BY,因为结果集已经排序。
当时对结果集进行排序的原因是 Oracle 使用了基于排序的算法来实现 group by。
在 10gR2 版本中,Oracle 添加了一个额外的基于 HASH 的 GROUP BY 算法。
你可以猜到故事的其余部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-19
    • 2017-10-31
    • 2014-12-18
    • 2021-06-26
    • 2015-02-10
    • 1970-01-01
    • 2020-11-08
    相关资源
    最近更新 更多