【问题标题】:Deduplicate rows in a BigQuery partition对 BigQuery 分区中的行进行重复数据删除
【发布时间】:2020-01-13 23:32:51
【问题描述】:

我有一个包含许多重复行的表 - 但我只想一次删除一个分区的重复数据。

我该怎么做?

例如,您可以从一个按日期分区并填充从 1 到 5 的随机整数的表开始:

CREATE OR REPLACE TABLE `temp.many_random`
PARTITION BY d
AS 
SELECT DATE('2018-10-01') d, fhoffa.x.random_int(0,5) random_int
FROM UNNEST(GENERATE_ARRAY(1, 100))
UNION ALL
SELECT CURRENT_DATE() d, fhoffa.x.random_int(0,5) random_int
FROM UNNEST(GENERATE_ARRAY(1, 100))

【问题讨论】:

    标签: sql merge google-bigquery duplicates database-partitioning


    【解决方案1】:

    让我们看看现有表中有哪些数据:

    SELECT d, random_int, COUNT(*) c
    FROM `temp.many_random`
    GROUP BY 1, 2
    ORDER BY 1,2
    

    这是很多重复的!

    我们可以使用MERGESELECT DISTINCT * 对单个分区进行重复数据删除,查询如下:

    MERGE `temp.many_random` t
    USING (
      SELECT DISTINCT *
      FROM `temp.many_random`
      WHERE d=CURRENT_DATE()
    )
    ON FALSE
    WHEN NOT MATCHED BY SOURCE AND d=CURRENT_DATE() THEN DELETE
    WHEN NOT MATCHED BY TARGET THEN INSERT ROW
    

    那么最终的结果是这样的:

    我们需要确保SELECTTHEN DELETE 行中的日期相同。这将删除该分区上的所有行,并插入 SELECT DISTINCT 中的所有行。

    灵感来源:

    要对整个表进行重复数据删除,请参阅:

    【讨论】:

      【解决方案2】:

      附加答案 - 对于无法使用 DISTINCT 的复杂行:

      MERGE `temp.many_random` t
      USING (
        # choose a single row to delete the duplicates
        SELECT a.*
        FROM (
          SELECT ANY_VALUE(a) a
          FROM `temp.many_random` a
          WHERE d='2018-10-01'
          GROUP BY d, random_int # id
        )
      )
      ON FALSE
      WHEN NOT MATCHED BY SOURCE AND d='2018-10-01' 
        # delete the duplicates
        THEN DELETE
      WHEN NOT MATCHED BY TARGET THEN INSERT ROW
      

      【讨论】:

      • ANY_VALUE() 和 GROUP BY 是一种很好的重复数据删除模式,当有很多重复时(在我的例子中:> 300 k)。比我以前使用的 ROW_NUMBER() 方法好得多!
      【解决方案3】:

      您还可以对一系列分区进行重复数据删除。

      -- 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 `my_project`.`data_set`.`the_table` AS INTERNAL_DEST
      USING (
        SELECT k.*
        FROM (
          SELECT ARRAY_AGG(original_data LIMIT 1)[OFFSET(0)] k 
          FROM `my_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

      【讨论】:

        猜你喜欢
        • 2020-05-26
        • 1970-01-01
        • 1970-01-01
        • 2017-07-22
        • 2019-05-08
        • 2017-08-20
        • 2019-08-20
        • 2019-11-20
        • 1970-01-01
        相关资源
        最近更新 更多