如何删除雪花数据库表中的重复记录

时间:2019-10-06 17:16:02

标签: snowflake-data-warehouse

如何从雪花表中删除重复的记录。谢谢

ID Name
1  Apple
1  Apple
2  Apple
3  Orange
3  Orange

结果应为:

ID Name
1  Apple
2  Apple
3  Orange

6 个答案:

答案 0 :(得分:2)

如果您有这样的主键:

CREATE TABLE fruit (key number, id number, name text);

insert into fruit values (1,1, 'Apple'), (2,1,'Apple'),
      (3,2, 'Apple'), (4,3, 'Orange'), (5,3, 'Orange');

那时

DELETE FROM fruit
WHERE key in (
  SELECT key 
  FROM (
      SELECT key
          ,ROW_NUMBER() OVER (PARTITION BY id, name ORDER BY key) AS rn
      FROM fruit
  )
  WHERE rn > 1
);

但是,如果您没有唯一密钥,则无法以这种方式删除。

CREATE TABLE new_table_name AS
SELECT id, name FROM (
    SELECT id
        ,name
        ,ROW_NUMBER() OVER (PARTITION BY id, name) AS rn
    FROM table_name
)
WHERE rn > 1

然后swap

ALTER TABLE table_name SWAP WITH new_table_name

答案 1 :(得分:2)

在此处添加一个不重新创建表格的解决方案。这是因为重新创建一个表会破坏很多现有的配置和历史。

相反,我们将只删除重复的行,并在事务中插入每行的一个副本:


-- find all duplicates
create or replace transient table duplicate_holder as (
    select $1, $2, $3
    from some_table
    group by 1,2,3
    having count(*)>1
);

-- time to use a transaction to insert and delete
begin transaction;

-- delete duplicates
delete from some_table a
using duplicate_holder b
where (a.$1,a.$2,a.$3)=(b.$1,b.$2,b.$3);

-- insert single copy
insert into some_table
select * 
from duplicate_holder;

-- we are done
commit;

优点:

  • 不重新创建表
  • 不修改原表
  • 只删除和插入重复的行(有利于时间旅行存储成本,避免不必要的重新集群)
  • 一切尽在交易中

答案 2 :(得分:1)

Snowflake没有有效的主键,其主要用于ERD工具。 Snowflake也没有ROWID之类的东西,因此也无法识别要删除的重复项。

可以临时添加“ is_duplicate”列,例如使用ROW_NUMBER()函数对所有重复项进行编号,然后使用“ is_duplicate”> 1删除所有记录,最后删除实用程序列。

另一种方法是创建重复表并交换,如其他建议的那样。 但是,必须保留限制和赠款。一种方法是:

CREATE TABLE new_table LIKE old_table COPY GRANTS;
INSERT INTO new_table SELECT DISTINCT * FROM old_table;
ALTER TABLE old_table SWAP WITH new_table;

上面的代码删除了 exact 个重复项。如果要为每个“ PK”结尾一行,则需要包括逻辑以选择要保留的 个副本。

这说明了在雪花数据仓库中添加更新时间戳列的重要性。

答案 3 :(得分:1)

这也困扰了我一段时间。随着雪花增加了对qualify的支持,您现在可以使用单个语句创建不包含子选择的去重复表:

CREATE TABLE fruit (id number, nam text);
insert into fruit values (1, 'Apple'), (1,'Apple'),
      (2, 'Apple'), (3, 'Orange'), (3, 'Orange');


CREATE OR REPLACE TABLE fruit AS 
SELECT * FROM 
fruit 
qualify row_number() OVER (PARTITION BY id, nam ORDER BY id, nam) = 1;
SELECT * FROM fruit;

当然,您会得到一个新表以及松散的表历史记录,主键,外键等。

答案 4 :(得分:0)

您的问题可以归结为:How can I delete one of two perfectly identical rows?。你不能您只能执行DELETE FROM fruit where ID = 1 and Name = 'Apple';,然后两行都将消失。或者您不保留两者。

对于某些数据库,存在使用内部行的解决方法,但是雪花中没有任何解决方法,请参见https://support.snowflake.net/s/question/0D50Z00008FQyGqSAL/is-there-an-internalmetadata-unique-rowid-in-snowflake-that-i-can-reference。您也不能限制删除,因此唯一的选择就是创建一个新表并交换。


关于汉斯·亨里克·埃里克森(Hans Henrik Eriksen)关于更新时间戳的重要性的补充说明:当以后添加重复项时,这是真正的帮助。例如,如果要保留较新的值,则可以执行以下操作:

-- setup
create table fruit (ID Integer, Name VARCHAR(16777216), "UPDATED_AT" TIMESTAMP_NTZ);
insert into fruit values (1, 'Apple', CURRENT_TIMESTAMP::timestamp_ntz)
, (2, 'Apple', CURRENT_TIMESTAMP::timestamp_ntz)
, (3, 'Orange', CURRENT_TIMESTAMP::timestamp_ntz);
-- wait > 1 nanosecond
insert into fruit values (1, 'Apple', CURRENT_TIMESTAMP::timestamp_ntz)
, (3, 'Orange', CURRENT_TIMESTAMP::timestamp_ntz);

-- delete older duplicates (DESC)
DELETE FROM fruit
  WHERE (ID
  , UPDATED_AT) IN (
     SELECT ID
     , UPDATED_AT
     FROM (
         SELECT ID
         , UPDATED_AT
         , ROW_NUMBER() OVER (PARTITION BY ID ORDER BY UPDATED_AT DESC) AS rn
         FROM fruit
     )
     WHERE rn > 1
  );

答案 5 :(得分:0)

基于上述想法.....以下查询在我的情况下效果很好。

CREATE OR REPLACE TABLE SCHEMA.table
 AS
SELECT
    DISTINCT * 
FROM
    SCHEMA.table
  ;