从 BigQuery 表中删除重复行

问题描述 投票:0回答:10

我有一个包含 >1M 行数据和 20 多列的表。

在我的表 (tableX) 中,我在一个特定列 (troubleColumn) 中识别出重复记录 (~80k)。

如果可能,我想保留原始表名称并从有问题的列中删除重复记录,否则我可以创建一个具有相同架构但没有重复项的新表(tableXfinal)。

我不精通 SQL 或任何其他编程语言,所以请原谅我的无知。

delete from Accidents.CleanedFilledCombined 
where Fixed_Accident_Index 
in(select Fixed_Accident_Index from Accidents.CleanedFilledCombined 
group by Fixed_Accident_Index 
having count(Fixed_Accident_Index) >1);
distinct google-bigquery
10个回答
93
投票

您可以通过运行重写表的查询来删除重复项(您可以使用相同的表作为目标,或者您可以创建一个新表,验证它是否具有您想要的内容,然后将其复制到旧表上)。

应该有效的查询在这里:

SELECT *
FROM (
  SELECT
      *,
      ROW_NUMBER()
          OVER (PARTITION BY Fixed_Accident_Index)
          row_number
  FROM Accidents.CleanedFilledCombined
)
WHERE row_number = 1

58
投票

2019 年更新:要使用

MERGE
删除单个分区上的重复行,请参阅:


Jordan 答案的另一种选择 - 当有太多重复项时,这个答案可以更好地扩展:

SELECT event.* FROM (
  SELECT ARRAY_AGG(
    t ORDER BY t.created_at DESC LIMIT 1
  )[OFFSET(0)]  event
  FROM `githubarchive.month.201706` t 
  # GROUP BY the id you are de-duplicating by
  GROUP BY actor.id
)

或者较短的版本(采用任意行,而不是最新的行):

SELECT k.*
FROM (
  SELECT ARRAY_AGG(x LIMIT 1)[OFFSET(0)] k 
  FROM `fh-bigquery.reddit_comments.2017_01` x 
  GROUP BY id
)

要删除现有表上的重复行:

CREATE OR REPLACE TABLE `deleting.deduplicating_table`
AS
# SELECT id FROM UNNEST([1,1,1,2,2]) id
SELECT k.*
FROM (
  SELECT ARRAY_AGG(row LIMIT 1)[OFFSET(0)] k 
  FROM `deleting.deduplicating_table` row
  GROUP BY id
)

43
投票

不知道为什么没有人提到 DISTINCT 查询。

以下是清除重复行的方法:

CREATE OR REPLACE TABLE project.dataset.table
AS
SELECT DISTINCT * FROM project.dataset.table

7
投票

如果您的模式没有任何记录 - Jordan 答案的

variation
下方将足够适合在同一张表或新表上写入,等等。

SELECT <list of original fields>
FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY Fixed_Accident_Index) AS pos,
  FROM Accidents.CleanedFilledCombined
)
WHERE pos = 1

在更一般的情况下 - 具有包含记录/网络字段等的复杂模式 - 上述方法可能是一个挑战。

我建议尝试使用 Tabledata: insertAll API,并将 rows[].insertId 设置为每行各自的 Fix_Accident_Index 。 在这种情况下,重复的行将被 BigQuery 消除

当然,这将涉及一些客户端编码 - 因此可能与这个特定问题无关。 我自己也没有尝试过这种方法,但觉得尝试一下可能会很有趣:o)


3
投票

如果您有一个大型分区表,并且仅在某个分区范围内有重复项。您不想过度扫描或处理整个表。使用下面的 MERGE SQL 以及分区范围上的谓词:

-- WARNING: back up the table before this operation
-- FOR large size timestamp partitioned table 
-- -------------------------------------------
-- -- To de-duplicate rows of a given range of a partition table, using surrage_key as unique id
-- -------------------------------------------

DECLARE dt_start DEFAULT TIMESTAMP("2019-09-17T00:00:00", "America/Los_Angeles") ;
DECLARE dt_end DEFAULT TIMESTAMP("2019-09-22T00:00:00", "America/Los_Angeles");

MERGE INTO `gcp_project`.`data_set`.`the_table` AS INTERNAL_DEST
USING (
  SELECT k.*
  FROM (
    SELECT ARRAY_AGG(original_data LIMIT 1)[OFFSET(0)] k 
    FROM `gcp_project`.`data_set`.`the_table` AS original_data
    WHERE stamp BETWEEN dt_start AND dt_end
    GROUP BY surrogate_key
  )

) AS INTERNAL_SOURCE
ON FALSE

WHEN NOT MATCHED BY SOURCE
  AND INTERNAL_DEST.stamp BETWEEN dt_start AND dt_end -- remove all data in partiion range
    THEN DELETE

WHEN NOT MATCHED THEN INSERT ROW

信用:https://gist.github.com/hui-zheng/f7e972bcbe9cde0c6cb6318f7270b67a


1
投票

Felipe 的答案是大多数情况下的最佳方法。这是完成相同任务的更优雅的方法:

CREATE OR REPLACE TABLE Accidents.CleanedFilledCombined
AS
SELECT 
  Fixed_Accident_Index, 
  ARRAY_AGG(x LIMIT 1)[SAFE_OFFSET(0)].* EXCEPT(Fixed_Accident_Index)
FROM Accidents.CleanedFilledCombined AS x
GROUP BY Fixed_Accident_Index;

为了安全起见,请确保在运行此命令之前备份原始表^^

如果可能的话,我不建议使用

ROW NUMBER() OVER()
方法,因为您可能会遇到 BigQuery 内存限制并出现意外错误。


1
投票

更简单的答案,无需子选择

  SELECT
      *,
      ROW_NUMBER()
          OVER (PARTITION BY Fixed_Accident_Index)
          row_number
  FROM Accidents.CleanedFilledCombined
  WHERE TRUE
  QUALIFY row_number = 1

Where True 是必要的,因为 Qualify 需要一个 where、group by 或having 子句


1
投票

当涉及大量重复数据删除时,QUALIFY 命令似乎是最有效且高效的选项,如此处

所述

0
投票
  1. 使用新表列更新 BigQuery 架构 bq_uuid,使其为 NULLABLE 并输入 STRING
  2. 例如,通过运行相同的命令 5 次来创建重复行

插入

beginner-290513.917834811114.messages
(id,类型,流,updated_at)值(19999,“hello”,“入站”,'2021-06-08T12:09:03.693646')

  1. 检查是否存在重复条目 从

    beginner-290513.917834811114.messages
    选择 *,其中 id = 19999

  2. 使用generate uuid函数生成每条消息对应的uuid 更新

    beginner-290513.917834811114.messages
    设置 bq_uuid = GENERATE_UUID() 其中 id>0

  3. 清除重复条目

beginner-290513.917834811114.messages
删除 bq_uuid 位于何处 (选择 bq_uuid 从 (选择bq_uuid, ROW_NUMBER() OVER( PARTITION BY Updated_at ORDER BY bq_uuid ) AS row_num 从
beginner-290513.917834811114.messages
) t 其中 t.row_num > 1 );


0
投票

创建2个相同的表并使用uniondistinct。

with tbl as (select * from my_table)
,    tbl_1 as (select * from my_table)

SELECT * from tbl

UNION DISTINCT

SELECT * FROM tbl_1
© www.soinside.com 2019 - 2024. All rights reserved.