关于sql:相当于MySQL GROUP BY的PostgreSQL

PostgreSQL equivalent for MySQL GROUP BY

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

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

这个查询很好:

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

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

column"MY_TABLE.SOME_COLUMN" must appear in the GROUP BY clause or be
used in an aggregate function

此查询的Postgres等效项是什么?

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


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

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

简单的情况

这将适用于PostgreSQL 9.1:

1
2
3
4
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查询的行为-您可以使用*

1
2
3
4
5
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;

之所以可行,是因为在窗口函数count(*) OVER (...)之后应用了DISTINCT ON(特定于PostgreSQL),例如DISTINCT(SQL-Standard)。窗口函数(带有OVER子句)需要PostgreSQL 8.4或更高版本,并且在MySQL中不可用。

无论主要约束还是唯一约束,都可以与任何表一起使用。

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

SQL Fiddle并列演示。

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

  • 在每个GROUP BY组中选择第一行?

count(*)count(id)

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


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

1
2
3
4
5
6
7
8
9
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

数据源:

1
2
3
4
5
6
7
8
9
10
11
12
13
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);

输出:

1
2
3
4
5
6
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 ON文档:http://www.postgresonline.com/journal/archives/4-Using-Distinct-ON-to-return-newest-order-for-each-customer.html


这是一个自联的CTE,可让您使用select *。 key0是预期的唯一键,{key1,key2}是解决当前非唯一行所需的其他键元素。 YMMV使用风险自负。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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子句。


mysql允许GROUP BY省略GROUP BY列表中未聚合的选定列,它通过返回针对按列分组的每个唯一组合找到的第一行来执行。这是非标准的SQL行为。

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

在postgres中没有等效的查询。