将使用 GROUP BY 的查询从 MySQL 转换为 Postgres 和 SQLite
Posted
技术标签:
【中文标题】将使用 GROUP BY 的查询从 MySQL 转换为 Postgres 和 SQLite【英文标题】:Translate query with GROUP BY from MySQL to Postgres and SQLite 【发布时间】:2016-04-07 11:24:33 【问题描述】:在 mysql 中,我使用了很多如下所示的结构:
LEFT JOIN(
SELECT field_one, field_two, field_three FROM (
SELECT field_one, field_two, field_three FROM table_one
ORDER BY field_three
) o GROUP BY field_one
) abc ON cur_table.some_field = abc.field_one
我使用它,因为它可以帮助我完成一项日常任务——在分组之前对一些数据进行排序。现在我想知道如何将这个 SQL 结构从 MySQL 迁移到 SQLite 和 PostgreSQL。
【问题讨论】:
用样本数据准备sqlfiddle.com。提供准确的答案会容易得多 为我工作(在 SQLite 中)。你为什么不试试呢? 我没有尝试过,因为我在 Postgresql 中的某个地方有红色,例如,他们以其他方式做类似的事情(这对我来说看起来相当丑陋)。所以我认为它不标准。 派生表中的order by
没有意义,并且服务器没有实际用途,因为查询中中间步骤的行的“顺序”无关紧要。另外:) o group by field_one
是无效的 SQL(您不能“分组”表别名)。另外:group by
没有任何意义,因为您没有使用任何聚合。我不明白你想用这个实现什么。您要解决的根本问题是什么?你为什么不直接加入这两个表呢?无用的order by
和错误的group by
是什么原因?
@a_horse_with_no_name。假设field_three
是一些auto_increment 字段,field_one
是外键,它指向当前表中的字段some_field
(在我的示例中具有别名cur_table
)。现实世界的任务是获取一些重要数据(来自 field_two),当前表中每个some_field
一个。任务可能是获取table_one
中第一个或最后一个插入的数据。因此,我确实需要order by
,它确实有道理,而且我确实需要分组,而且我不需要任何聚合。
【参考方案1】:
我怀疑您查询的目的是使用 MySQL 怪癖为现有 GROUP BY
子句中也未列出的未聚合列选择任意行(这 违反 SQL 标准 em> 并且大多数其他 RDBMS 不支持)。通过在子查询中排序,您可以让 MySQL 选择每个组中具有最小 field_three
的行,所以我假设您想要:
每个field_one
的最小field_three
和同一行中的field_two
一起使用。
您的原始查询在此处遵循 SQL 标准的 Postgres 中不工作。如果SELECT
有GROUP BY
子句,则必须列出或聚合所有输出列。考虑:
带窗口函数的标准 SQL
一种可能的标准SQL解决方案是在子查询中使用窗口函数row_number()
:
SELECT field_one, field_two, field_three
FROM (
SELECT field_one, field_two, field_three
, row_number() OVER(PARTITION BY field_one ORDER BY field_three) rn
FROM table_one
) sub
WHERE sub.rn = 1
适用于 Postgres,但不适用于不支持窗口函数的 SQLite 或 MySQL。
基本标准 SQL
此查询适用于所有三个 RDBMS(几乎也适用于其他任何地方),但需要 field_three
中的唯一最大值(如果每个 field_one
存在最大 field_three
的关系,则返回多行)。
SELECT t1.*
FROM table_one t1
LEFT JOIN table_one t2 ON t1.field_one = t2.field_one
AND t1.field_three < t2.field_three
WHERE t2.field_one IS NULL
如果您有任何独特的(一组)列,则可以解决平局,但这很笨拙。相关:
Fetch the row which has the Max value for a columnPostgres
(除了支持所有标准 SQL 解决方案之外)Postgres 还具有强大的 DISTINCT ON
(标准 DISTINCT
的扩展,但不反对像 MySQL 和 SQLite 怪癖这样的标准):
SELECT DISTINCT ON (field_one)
field_one, field_two, field_three
FROM table_one
ORDER BY field_one, field_three
您可以通过向ORDER BY
添加更多列来解决平局。详情:
SQLite
... 与 MySQL 有类似的怪癖(违反 SQL 标准)。 From the release notes:
查询形式:“SELECT max(x), y FROM table”返回包含最大 x 值的同一行上的 y 值。
所以:
SELECT field_one, field_two, max(field_three) AS field_three
FROM table_one
GROUP BY field_one
field_two
取自 max(field_three)
的行。相关:
加入和加入条件在任何地方都一样:
LEFT JOIN (SELECT ...) abc ON cur_table.some_field = abc.field_one
【讨论】:
+1,你也许可以通过 APPLY 操作击败 row_number() 解决方案……但它仍然不受 MySql 支持。 谢谢您,先生!您最后的评论是否意味着我的问题的解决方案将在SQLite
和 Postgres
以及可能在其他数据库中工作,尽管正如 a_horse_with_no_name 和 wildplasser 所说,group by
将从查询计划中删除?跨度>
附言。您正确理解了我查询的确切目的。
@Jacobian:您的原件在 Postgres 中不起作用。考虑上面添加的解释。以上是关于将使用 GROUP BY 的查询从 MySQL 转换为 Postgres 和 SQLite的主要内容,如果未能解决你的问题,请参考以下文章
使用函数 SUM() 和 Group by 将 Mysql 查询转换为 SQL 查询