Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在PostgreSQL中查找重复记录_Sql_Postgresql_Duplicates - Fatal编程技术网

如何在PostgreSQL中查找重复记录

如何在PostgreSQL中查找重复记录,sql,postgresql,duplicates,Sql,Postgresql,Duplicates,我有一个名为user_links的PostgreSQL数据库表,该表当前允许以下重复字段: year, user_id, sid, cid 唯一约束当前是第一个名为id的字段,但是我现在希望添加一个约束,以确保年份、用户id、sid和cid都是唯一的,但是我无法应用该约束,因为已经存在违反该约束的重复值 有没有找到所有重复项的方法?基本思路是使用带有计数聚合的嵌套查询: select * from yourTable ou where (select count(*) from yourTab

我有一个名为user_links的PostgreSQL数据库表,该表当前允许以下重复字段:

year, user_id, sid, cid
唯一约束当前是第一个名为id的字段,但是我现在希望添加一个约束,以确保年份、用户id、sid和cid都是唯一的,但是我无法应用该约束,因为已经存在违反该约束的重复值


有没有找到所有重复项的方法?

基本思路是使用带有计数聚合的嵌套查询:

select * from yourTable ou
where (select count(*) from yourTable inr
where inr.sid = ou.sid) > 1
您可以调整内部查询中的where子句以缩小搜索范围

对于评论中提到的问题,还有另一个很好的解决方案,但并不是每个人都读过:

select Column1, Column2, count(*)
from yourTable
group by Column1, Column2
HAVING count(*) > 1
或更短:

SELECT (yourTable.*)::text, count(*)
FROM yourTable
GROUP BY yourTable.*
HAVING count(*) > 1

您可以在要复制的字段上连接到同一个表,然后在id字段上反连接。从第一个表别名tn1中选择id字段,然后在第二个表别名的id字段上使用array_agg函数。最后,为了使array_agg函数正常工作,您将按照tn1.id字段对结果进行分组。这将生成一个结果集,其中包含记录的id和符合联接条件的所有id的数组

select tn1.id,
       array_agg(tn2.id) as duplicate_entries, 
from table_name tn1 join table_name tn2 on 
    tn1.year = tn2.year 
    and tn1.sid = tn2.sid 
    and tn1.user_id = tn2.user_id 
    and tn1.cid = tn2.cid
    and tn1.id <> tn2.id
group by tn1.id;
显然,对于一个id,将在duplicate_entries数组中的id在结果集中也将有自己的条目。您必须使用此结果集来决定要将哪个id作为“真相”的来源。该记录不应被删除。也许你可以这样做:

with dupe_set as (
select tn1.id,
       array_agg(tn2.id) as duplicate_entries, 
from table_name tn1 join table_name tn2 on 
    tn1.year = tn2.year 
    and tn1.sid = tn2.sid 
    and tn1.user_id = tn2.user_id 
    and tn1.cid = tn2.cid
    and tn1.id <> tn2.id
group by tn1.id
order by tn1.id asc)
select ds.id from dupe_set ds where not exists 
 (select de from unnest(ds.duplicate_entries) as de where de < ds.id)
假设ID增加int PK,则选择具有重复项的最低编号ID。这些将是您将保留的ID。

来自以下智能解决方案:

select * from (
  SELECT id,
  ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id asc) AS Row
  FROM tbl
) dups
where 
dups.Row > 1

为了简化,我假设您希望仅对列year应用唯一约束,并且主键是名为id的列

为了找到重复的值,您应该运行

SELECT year, COUNT(id)
FROM YOUR_TABLE
GROUP BY year
HAVING COUNT(id) > 1
ORDER BY COUNT(id);
使用上面的sql语句可以得到一个表,其中包含表中所有重复的年份。为了删除除最新的重复项之外的所有重复项,您应该使用上面的sql语句

DELETE
FROM YOUR_TABLE A USING YOUR_TABLE_AGAIN B
WHERE A.year=B.year AND A.id<B.id;

在您的情况下,由于约束,您需要删除重复的记录

查找重复的行 按创建日期组织它们-在这种情况下,我保留最旧的 使用删除记录以筛选正确的行 复制为 选择id, 计数* 来自产品 按id分组 计数*>1, 订购为 选择p.id, 创建于, 按p.id在分区上排序按p.U在rnk处创建的顺序 从产品o d.id=p.id上重复的联接, 产品\u至\u删除为 选择id, 创建于 从命令 其中rnk=2 删去 来自产品 使用产品来删除 其中products.id=products\u to\u delete.id AND products.created_at=products_to_delete.created_at;
您也可以使用HAVING:从tbl group by col1中选择co1、col2、count*,col2 HAVING count*>1Thanks@alexkovelsky HAVING语句对我来说更容易修改,运行更快。为了更高的可视性,我会建议一个答案。这些选项对我有效,其他人将结果分组,这些选项为我提供了所有重复的记录,而不仅仅是重复的记录,谢谢!我认为你的回答有点慢。在一个10k行*18列的表上,查询花了8秒时间,就在那里,兄弟。见鬼,是的。谢谢这太快了!在几分之一秒的时间内完成了数百万行的工作。其他答案只是挂在那里……如我所见,这个查询不考虑组内的所有行。它只显示某个对象的副本,部分副本的rownum=1。如果我需要,请纠正我wrong@vladimirFilipchenko要使其与所有行一起使用,请向Alexkovelsky解决方案添加一个级别:从SELECT*中选择*作为下一行,从SELECT*中选择1作为下一行,从tbl窗口中选择行数作为下一行,按列1分区,按列3 x y排序,其中行>1或下一行>1@VladimirFilipchenko只需将行数替换为COUNT*,并在按id排序后在无界前后行之间添加行,这比我找到的其他解决方案要好得多。使用DELETE…USING和一些小的调整简单而有效,同样适用于删除重复。可以通过替换a.id在没有唯一列的静态表上使用