使用GROUP BY将查询从MySQL转换为Postgres和SQLite

时间:2016-01-03 20:19:31

标签: mysql sql postgresql sqlite greatest-n-per-group

在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

1 个答案:

答案 0 :(得分:2)

我怀疑你的查询的目的是使用MySQL怪癖为未聚合的列选择任意行,这些列也未在现有GROUP BY子句中列出(违反SQL标准并且大多数其他RDBMS都不支持。通过在子查询中排序,你可以让MySQL选择每个gropup最小field_three的行,所以我假设你想要:

每个field_three的最小field_one,以及来自同一行的field_two


你的原始查询在Postgres中工作,这符合SQL标准。如果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_three存在最大field_one个关联,则返回多行})。

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

如果您有任何唯一(一组)列,您可以解决关系,但它不实用。相关:

的Postgres

(除了支持所有标准的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:

  

表格的查询:&#34; SELECT max(x),y​​ FROM table&#34;返回包含最大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