【问题标题】:PostgreSQL equivalent for MySQL GROUP BYMySQL GROUP BY 的 PostgreSQL 等效项
【发布时间】:2012-05-11 00:41:41
【问题描述】:

我需要在表中查找重复项。在 MySQL 中我只写:

SELECT *,count(id) count FROM `MY_TABLE`
GROUP BY SOME_COLUMN ORDER BY count DESC

这个查询很好:

  • 根据 SOME_COLUMN 查找重复项,并给出其重复次数。
  • 按重复的 desc 顺序排序,这对于快速扫描主要副本很有用。
  • 为所有剩余的列选择一个随机值,让我了解这些列中的值。

Postgres 中的类似查询提示我一个错误:

列“MY_TABLE.SOME_COLUMN”必须出现在 GROUP BY 子句中,否则 在聚合函数中使用

这个查询的 Postgres 等价物是什么?

PS:我知道 MySQL 的行为偏离了 SQL 标准。

【问题讨论】:

  • 请添加拒绝投票的理由。如果这是一个糟糕的问题,我会亲自投票删除。
  • 这不是一个坏问题。我删除了煽动性的部分并进行了一些编辑。
  • 我不知道为什么这里的一些人在他们真的不理解主题的情况下仍然对有趣的问题或答案投反对票......

标签: mysql sql postgresql group-by aggregate-functions


【解决方案1】:

反引号是一种非标准的 MySQL 事物。使用规范的双引号来引用标识符(在 MySQL 中也可以)。也就是说,如果您的表实际上被命名为"MY_TABLE"(全部大写)。如果您(更明智地)将其命名为 my_table(全部小写),则可以删除双引号或使用小写。

另外,我使用ct 而不是count 作为别名,因为使用函数名作为标识符是不好的做法。

简单案例

这适用于 PostgreSQL 9.1

SELECT *, count(id) ct
FROM   my_table
GROUP  BY primary_key_column(s)
ORDER  BY ct DESC;

它需要GROUP BY 子句中的主键列。结果与 MySQL 查询相同,但 ct 将始终为 1(如果 id IS NULL 则为 0)- 无用查找重复项。

除主键列以外的分组方式

如果您想按其他列进行分组,事情会变得更加复杂。此查询模仿 MySQL 查询的行为 - 您可以使用 *

SELECT DISTINCT ON (1, some_column)
       count(*) OVER (PARTITION BY some_column) AS ct
      ,*
FROM   my_table
ORDER  BY 1 DESC, some_column, id, col1;

之所以有效,是因为DISTINCT ON(特定于PostgreSQL)与DISTINCT(SQL 标准)一样,在窗口函数count(*) OVER (...) 之后应用Window functions(带有 OVER 子句)需要 PostgreSQL 8.4 或更高版本,在 MySQL 中不可用。

适用于任何表,无论主要约束或唯一约束如何。

DISTINCT ONORDER BY 中的 1 只是引用 SELECT 列表中项目序号的简写。

SQL Fiddle 并排演示。

此密切相关的答案中的更多详细信息:


count(*)count(id)

如果您要查找重复项,使用count(*) 比使用count(id) 更好。如果id 可以是NULL,则存在细微差别,因为不计算NULL 的值 - 而count(*) 计算所有行。如果id 定义为NOT NULL,结果是一样的,但count(*) 通常更合适(也稍微快一点)。

【讨论】:

  • 谢谢@Erwin。我正在使用 9.0.4,它说“没有函数与给定的名称和参数类型匹配”。升级到 9.1 后再试。
  • @jerrymouse:升级到 9.1 是一个好主意,原因有很多。添加了 9.1 之前的信息并通常编辑了我的答案。初稿不准确。
  • @aleroot:是窗口函数和DISTINCT的结合。重要的是DISTINCT 应用在 窗口函数之后(在聚合函数之后应用)。
【解决方案2】:

mysql 允许group by 省略group by 列表中选择的非聚合列,它通过返回为每个唯一组合找到的 first 行来执行按列分组。这是非标准的 SQL 行为。

另一方面,postgres 符合 SQL 标准。

postgres 中没有等效的查询。

【讨论】:

  • 我的(编辑过的)查询应该是一个等同于 MySQL 查询的 PostgreSQL——如果我没有遗漏什么的话。
  • Postgres 有,而且它比 MySql 提供的更明智。查看对 GROUP BY ienablemuch.com/2010/08/postgresql-recognizing-functional.html的函数依赖
  • 如果你真的想在 Postgresql 中使用随机选择的非聚合列模拟 MySQL 的 GROUP BY,请使用 DISTINCT ON。但我从不为此使用 DISTINCT ON,DISTINCT ON 还有其他合法用途,例如:stackoverflow.com/questions/1104977/… 而这个:stackoverflow.com/questions/10392567/…
  • @MichaelBuen:我不是在为 MySQL 的肮脏伎俩辩护,远非如此。我正在回答所提出的问题。我在回答中使用first_val() 的方式与DISTINCT ON 中未包含的列值一样随机。这两种方法都不完全选择随机值,而是特定于实现的任意值。就像 MySQL。
  • @ErwinBrandstetter 我不是指你的答案,我指的是这里的答案 :-) 我只是在这里松散地使用随机这个词,它就像一行一样随机选择基于它是按字母排序的第一行或数据库行中的物理位置。 Teehee,因为这个,我可能会命名我的孩子亚伦;但是,查询可能按姓氏排序,但我不能更改我们的姓氏,所以这就是我所说的随机。 Postgres 也未能幸免于 DISTINCT ON 的批评,但 MySql 的 GROUP BY 犯下的暴行要多得多
【解决方案3】:

这是一个自加入的 CTE,它允许您使用 select *。 key0 是 预期 唯一键,{key1,key2} 是处理当前非唯一行所需的附加键元素。使用风险自负,YMMV。

WITH zcte AS (
        SELECT DISTINCT tt.key0
        , MIN(tt.key1) AS key1
        , MIN(tt.key2) AS key2
        , COUNT(*) AS cnt
        FROM ztable tt
        GROUP BY tt.key0
        HAVING COUNT(*) > 1
        )
SELECT zt.*
        , zc.cnt AS cnt
FROM ztable zt
JOIN zcte zc ON zc.key0 = zt.key0 AND zc.key1 =  zt.key1 AND zc.key2 = zt.key2
ORDER BY zt.key0, zt.key1,zt.key2
      ;

顺便说一句:要获得 OP 的预期行为,应省略 HAVING COUNT(*) > 1 子句。

【讨论】:

    【解决方案4】:

    这是另一种方法,使用 DISTINCT ON:

    select 
    
      distinct on(ct, some_column) 
    
      *,
      count(id) over(PARTITION BY some_column) as ct
    
    from my_table x
    order by ct desc, some_column, id
    

    数据来源:

    CREATE TABLE my_table (some_column int, id int, col1 int);
    
    INSERT INTO my_table  VALUES
     (1, 3,  4)
    ,(2, 4,  1)
    ,(2, 5,  1)
    ,(3, 6,  4)
    ,(3, 7,  3)
    ,(4, 8,  3)
    ,(4, 9,  4)
    ,(5, 10, 1)
    ,(5, 11, 2)
    ,(5, 11, 3);
    

    输出:

    SOME_COLUMN ID          COL1        CT
    5           10          1           3
    2           4           1           2
    3           6           4           2
    4           8           3           2
    1           3           4           1
    

    现场测试:http://www.sqlfiddle.com/#!1/e2509/1

    DISTINCT 文档:http://www.postgresonline.com/journal/archives/4-Using-Distinct-ON-to-return-newest-order-for-each-customer.html

    【讨论】:

      猜你喜欢
      • 2011-06-19
      • 2010-12-18
      • 2017-08-24
      • 2021-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多