6

我需要在表中找到重复项。在 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 标准。

4

4 回答 4

12

反引号是非标准的 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(或 0 if id IS NULL) - 对查找重复项无用。

按主键列以外的方式分组

如果您想按其他列分组,事情会变得更加复杂。这个查询模仿你的 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 标准),是在window function之后count(*) OVER (...)应用的。窗口函数(带有OVER子句)需要 PostgreSQL 8.4或更高版本,并且在 MySQL 中不可用。

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

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

SQL Fiddle并排演示。

这个密切相关的答案中的更多细节:


count(*)对比count(id)

如果您正在寻找重复项,那么使用count(*)比使用更好count(id)idif can be存在细微差别NULL,因为NULL不计算值 - 而count(*)计算所有行。如果id是定义NOT NULL的,结果是相同的,但count(*)通常更合适(也稍微快一点)。

于 2012-05-01T13:44:16.110 回答
3

这是另一种方法,使用 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

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

于 2012-05-03T00:01:27.610 回答
1

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

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

postgres 中没有等效的查询。

于 2012-05-01T13:45:15.027 回答
1

这是一个自联接的 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应省略该子句。

于 2012-05-01T15:08:18.360 回答