我需要在表格中找到重复项。在MySQL中我只写:
SELECT *,count(id) count FROM `MY_TABLE`
GROUP BY SOME_COLUMN ORDER BY count DESC
这个查询很好:
Postgres中的类似查询给我一个错误:
列“MY_TABLE.SOME_COLUMN”必须出现在GROUP BY子句中或者是 用于聚合函数
该查询的Postgres等价物是什么?
PS:我知道MySQL的行为偏离了SQL标准。
答案 0 :(得分:12)
Back-ticks是一种非标准的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-Standard),在窗口函数count(*) OVER (...)
之后应用。 Window functions(带有OVER
子句)需要PostgreSQL 8.4 或更高版本,并且在MySQL中不可用。
适用于任何表格,无论主要或唯一约束如何。
1
和DISTINCT ON
中的ORDER BY
只是简短地引用SELECT
列表中项目的序号。
SQL Fiddle并肩展示。
这个密切相关答案的更多细节:
count(*)
与count(id)
如果您要查找重复项,最好使用count(*)
而不是使用count(id)
。如果id
可以是NULL
,则会有一个细微差别,因为NULL
值不计算 - 而count(*)
计算所有行。如果id
定义为NOT NULL
,则结果相同,但count(*)
通常更合适(也会更快)。
答案 1 :(得分: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
DISTINCT ON文档:http://www.postgresonline.com/journal/archives/4-Using-Distinct-ON-to-return-newest-order-for-each-customer.html
答案 2 :(得分:1)
mysql允许group by
省略来自group by
列表的非聚合选定列,它通过返回找到的第一行行来执行按列分组的每个唯一组合。这是非标准的SQL行为。
postgres中没有等效的查询。
答案 3 :(得分: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
;
BTW:要获得OP的预期行为,应省略HAVING COUNT(*) > 1
子句。