Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.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
Sql 如何删除没有唯一标识符的重复行_Sql_Database_Postgresql_Duplicates_Netezza - Fatal编程技术网

Sql 如何删除没有唯一标识符的重复行

Sql 如何删除没有唯一标识符的重复行,sql,database,postgresql,duplicates,netezza,Sql,Database,Postgresql,Duplicates,Netezza,我的表中有重复的行,我想以最有效的方式删除重复的行,因为表很大。经过研究,我提出了以下问题: WITH TempEmp AS ( SELECT name, ROW_NUMBER() OVER(PARTITION by name, address, zipcode ORDER BY name) AS duplicateRecCount FROM mytable ) -- Now Delete Duplicate Records DELETE FROM TempEmp WHERE duplicate

我的表中有重复的行,我想以最有效的方式删除重复的行,因为表很大。经过研究,我提出了以下问题:

WITH TempEmp AS
(
SELECT name, ROW_NUMBER() OVER(PARTITION by name, address, zipcode ORDER BY name) AS duplicateRecCount
FROM mytable
)
-- Now Delete Duplicate Records
DELETE FROM TempEmp
WHERE duplicateRecCount > 1;

但它只在SQL中工作,在Netezza中不起作用。似乎不喜欢WITH子句后面的DELETE?

如果没有其他唯一标识符,可以使用ctid:


在每个表中都有一个唯一的、自动递增的id是个好主意。执行这样的删除操作是一个重要原因。

下面是我使用group by得出的结论


它删除重复项,保留有重复项的最旧记录。

有效语法在中指定

我会修改您的表,添加一个唯一的自动递增主键id,以便您可以运行如下查询,该查询将保留每组重复项中的第一个,即id最低的一个。请注意,在Postgres中添加键比其他一些DBs要复杂一些

DELETE FROM mytable d USING (
  SELECT min(id), name, address, zip 
  FROM mytable 
  GROUP BY name, address, zip HAVING COUNT() > 1
) AS k 
WHERE d.id <> k.id 
AND d.name=k.name 
AND d.address=k.address 
AND d.zip=k.zip;

我们可以使用窗口功能非常有效地删除重复行:

DELETE FROM tab 
  WHERE id IN (SELECT id 
                  FROM (SELECT row_number() OVER (PARTITION BY column_with_duplicate_values), id 
                           FROM tab) x 
                 WHERE x.row_number > 1);
一些带有ctid的PostgreSQL优化版本:

DELETE FROM tab 
  WHERE ctid = ANY(ARRAY(SELECT ctid 
                  FROM (SELECT row_number() OVER (PARTITION BY column_with_duplicate_values), ctid 
                           FROM tab) x 
                 WHERE x.row_number > 1));
在一个完美的世界中,每个表都有某种唯一的标识符。 在没有任何唯一列或其组合的情况下,使用:

从tbl中删除 我不在哪里 SELECT minctid-ctid根据定义不为空 来自tbl 按名称、地址、zipcode分组;-列出定义重复项的列 上面的查询很短,只方便地列出一次列名。不在选择中。。。当可能涉及空值时,这是一种复杂的查询样式,但系统列ctid从不为空。见:

使用“存在”通常更快。USING子句的自连接也是如此。两者应产生相同的查询计划

重要区别:这些其他查询将空值视为不相等,而GROUP BY或DISTINCT or将空值视为相等。对于定义为NOTNULL的列不重要。否则,根据您对复制的定义,您将需要一种或另一种方法。或用于比较可能排除某些索引的值

免责声明:

ctid是Postgres的一个实现细节,它不在SQL标准中,可以在没有警告的情况下在主要版本之间进行更改,即使这种情况非常不可能发生。由于后台进程或并发写入操作,其值可以在命令之间更改,但不能在同一命令内更改

相关的:

旁白:

DELETE语句的目标不能是CTE,只能是基础表。这是SQL Server的一种溢出效应——您的整个方法也是如此。

来自文档

IRC中的一个常见问题是如何删除一组列上重复的行,只保留ID最低的行。 此查询对具有相同column1、column2和column3的tablename的所有行执行此操作

DELETE FROM tablename
WHERE id IN (SELECT id
          FROM (SELECT id,
                         ROW_NUMBER() OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
                 FROM tablename) t
          WHERE t.rnum > 1);

有时会使用时间戳字段而不是ID字段。

如果要在表中的重复行中保留一行,请使用时间戳字段

create table some_name_for_new_table as 
(select * from (select *,row_number() over (partition by pk_id) row_n from 
your_table_name_where_duplicates_are_present) a where row_n = 1);
这将创建一个可以复制的表


复制表之前,请删除列“row\u n”

我喜欢@erwin brandstetter的解决方案,但想用USING关键字显示一个解决方案:

更新:为了提高速度,我在这里测试了一些不同的解决方案。如果您不希望有太多的重复项,那么此解决方案的性能要比那些没有重复项的解决方案好得多。。。子句,因为它们在子查询中生成许多行

如果您重写查询以在中使用。。。然后,它的性能与这里介绍的解决方案类似,但SQL代码变得不那么简洁

更新2:如果在其中一个键列中有空值,而您确实不应该这样做,那么您可以在该列的条件中使用COALESCE,例如

  AND COALESCE(T1.col_with_nulls, '[NULL]') = COALESCE(T2.col_with_nulls, '[NULL]')

如果您希望每一行都有一个唯一的标识符,那么只需添加一个序列号或guid,并将其视为代理键


对于较小的表,我们可以使用rowid伪列删除重复的行

您可以在下面使用此查询:


从表1 t1中删除,其中t1.rowid>从表1 t2中选择mint2.rowid,其中t1.column=t2。列

如果是一次性作业,为什么不在postgresql控制台中运行它?不是一次性作业,而是每周作业,我们总是会得到一些重复值。谢谢为什么会有重复的值?如果你不把它放在第一位呢?重复项是由列名称、地址、zipcode定义的吗?还有其他专栏吗?这些都无关紧要吗?不同的任何列的组合都是唯一的吗?如果某些列在重复项之间存在差异,您希望保留每组中的哪一行?适用于POSTGRESQL也适用于AWS REDSHIFT我的表中没有任何名为ctid的字段。您能解释一下从何处获得此字段吗?thanksctid是一个隐藏字段。检索表定义时,它不会显示。这是一种内部行号。如果不存在行号,将删除不重复的行。嘘
如果存在,请选择1`@GordonLinoff-感谢您的澄清。我知道这是离题的;这就是OT:在我的问题的前缀中的意思;在我的小表格中,我做了:从表格中选择ctid,*。ctid表示为0,1,0,2等,因此我能够对重复的行执行一个简单的delete语句:delete from table,其中ctid='0,1'我的表中没有id,这是netezza数据库。它们没有像sql Server那样的自动递增数字。它是否有另一个唯一标识行的列?HAVING子句是此查询的noise。在任何情况下,每个现有id的计数都大于等于1。你可以删除它。我喜欢这个解决方案,因为它非常简洁。对于我在下面发布的解决方案的性能有什么想法吗?我实际上能够测试它。我有一个大约350k行的表,它有39个重复项,超过7列,没有索引。我首先尝试了按解决方案分组,但耗时超过30秒,因此我将其杀死。然后我尝试了使用解决方案,大约在16秒钟内完成。@isapir:就像我在2014年提到的:notin是方便快捷的语法,但EXISTS更快。与使用USING子句的完全有效查询相同。但有一个微妙的区别。我在上面加了个便条。酷。感谢您的澄清。Erwin的答案更好,因为它正确处理空值,并且不需要在列名中键入两次。正如我在答案开头所写的:我喜欢@Erwin brandstetter的解决方案,但想展示一个解决方案。。。。但是,在发现性能优势后,我更喜欢使用解决方案,尤其是对于大型表。我添加了一个演示如何处理空值的示例。非常好,特别是可以先看一看。为了检查数据列中的空值,我根据表的\dS输出为每列生成了一个T1.col=T2.col或T1.col为空且T2.col为空的条件。现在我可以添加我的主键约束。您可以使用coalesce测试空值,正如我的答案更新2中所希望的。谢谢,这比其他解决方案快得多。我在1小时后放弃了一些版本,这几乎是瞬间完成的Lynetezza不支持主键或唯一键约束,它没有。
create table some_name_for_new_table as 
(select * from (select *,row_number() over (partition by pk_id) row_n from 
your_table_name_where_duplicates_are_present) a where row_n = 1);
DELETE   FROM table_with_dups T1
  USING       table_with_dups T2
WHERE  T1.ctid    < T2.ctid       -- delete the "older" ones
  AND  T1.name    = T2.name       -- list columns that define duplicates
  AND  T1.address = T2.address
  AND  T1.zipcode = T2.zipcode;
SELECT * FROM table_with_dups T1
  ,           table_with_dups T2
WHERE  T1.ctid    < T2.ctid       -- select the "older" ones
  AND  T1.name    = T2.name       -- list columns that define duplicates
  AND  T1.address = T2.address
  AND  T1.zipcode = T2.zipcode;
  AND COALESCE(T1.col_with_nulls, '[NULL]') = COALESCE(T2.col_with_nulls, '[NULL]')
CREATE TABLE thenames
        ( name text not null
        , address text not null
        , zipcode text not null
        );
INSERT INTO thenames(name,address,zipcode) VALUES
('James', 'main street', '123' )
,('James', 'main street', '123' )
,('James', 'void street', '456')
,('Alice', 'union square' , '123')
        ;

SELECT*FROM thenames;
        -- add a surrogate key
ALTER TABLE thenames
        ADD COLUMN seq serial NOT NULL PRIMARY KEY
        ;
SELECT*FROM thenames;

DELETE FROM thenames del
WHERE EXISTS(
        SELECT*FROM thenames x
        WHERE x.name=del.name
        AND x.address=del.address
        AND x.zipcode=del.zipcode
        AND x.seq < del.seq
        );

        -- add the unique constrain,so that new dupplicates cannot be created in the future
ALTER TABLE thenames
        ADD UNIQUE (name,address,zipcode)
        ;

SELECT*FROM thenames;