【问题标题】:BigQuery - DELETE statement to remove duplicatesBigQuery - 删除重复项的 DELETE 语句
【发布时间】:2018-06-16 06:04:20
【问题描述】:

有很多很棒的关于 SQL 的帖子,它们选择唯一的行并写入(截断)一个表,以便删除 dus。例如

WITH ev AS (
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY loadTime DESC) AS rowNum
  FROM `duplicates`
 )
SELECT
  * EXCEPT(rowNum)
FROM
  ev
WHERE rowNum = 1

我尝试使用 DML 和 DELETE 稍微不同地探索这一点(例如,如果您不想使用 BQ savedQuery,只需执行 SQL)。我想做的大致是:

WITH dup_events AS (
  SELECT
        *,
        ROW_NUMBER() OVER (PARTITION BY id ORDER BY loadTime DESC) AS rowNum
      FROM `duplicates`
 )
DELETE FROM
  dup_events
WHERE rowNum > 1

但在控制台中出现此错误:

Syntax error: Expected "(" or keyword SELECT but got keyword DELETE at [10:1]

是否可以使用 DELETE 来实现(标准 SQL)?

谢谢!

【问题讨论】:

    标签: google-bigquery


    【解决方案1】:

    这一定是最简单的方法:

    create or replace table `myproject.mydataset.duplicates` as (
    select distinct *
    from `myproject.mydataset.duplicates`)
    

    如果你有数组数据类型,试试这个:

    -- build a test table with a duplicate and an array datatype column --
    create or replace table DW.pmoTest as (
    select 1 as ID, 'peter' as firstname,ARRAY<INT64>[1, 2, 3]  as int_array, current_date as createdate
    union all
    select 1 as ID, 'peter' as firstname,ARRAY<INT64>[1, 7, 3] as int_array, current_date as createdate
    union all
    select 2 as ID, 'chamri' as firstname,ARRAY<INT64>[1, 2, 39, 4] as int_array, current_date as createdate
    );
    
    -- recreate table without duplicate row
    create or replace table DW.pmoTest as (
    SELECT col.* FROM (
      SELECT ARRAY_AGG(tbl ORDER BY createdate LIMIT 1)[OFFSET(0)]  col
      FROM DW.pmoTest tbl
      GROUP BY ID
      )
    );
    

    【讨论】:

    • 将括号中的部分绑定时出现此错误:ARRAY 类型的列实例不能在 SELECT DISTINCT 中使用
    【解决方案2】:

    以上这些答案仅适用于小尺寸表。如果您有一个大分区表,并且只想删除给定范围内的重复项,请使用以下 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

    【讨论】:

      【解决方案3】:

      syntax documentation 开始,DELETE 的参数需要是一个表,并且没有使用WITH 子句的规定。这是有道理的,因为您不能从本质上是逻辑视图(CTE)中删除。您可以通过将逻辑放入过滤器中来表达您想要的内容,例如

      DELETE
      FROM duplicates AS d
      WHERE (SELECT ROW_NUMBER() OVER (PARTITION BY id ORDER BY loadTime DESC)
             FROM `duplicates` AS d2
             WHERE d.id = d2.id AND d.loadTime = d2.loadTime) > 1;
      

      【讨论】:

      • 不知何故,我认为 where 子句中不允许使用分析函数。我现在正在运行,无法自行检查 - 你能确认它确实有效吗?
      • 在权衡方面,您对使用这种方法与选择和覆盖有何看法? DML Quota 当然是其中之一,很快它将在分区表上得到支持(我在测试版中)。似乎有利的一件事是数据丢失的风险 - 我不太确定另一种方法是,如果您在执行重复数据删除查询的同时有另一个进程加载了被重复数据删除的表(大表可能需要几分钟执行这样的去重查询)- 如果查询和加载时间未对齐,是否有丢失新加载数据的风险?对此有什么想法?干杯!
      • 实际上,我只是尝试过这个并得到了这个错误 - 错误:在 [5:4] 的 WHERE 子句中不允许分析函数
      • 我认为它仍然可以工作,但我需要尝试运行实际查询:) 让我看看...
      • 谢谢 Elliott - 这次我遇到了这个错误错误:不支持引用其他表的相关子查询,除非它们可以去相关,例如通过将它们转换为有效的 JOIN。
      【解决方案4】:

      实际上在下面 :o) 有效

      #standardSQL
      DELETE FROM `yourproject.yourdataset.duplicates`
      WHERE STRUCT(id, loadTime) NOT IN (
              SELECT AS STRUCT id, MAX(loadTime) loadTime 
              FROM `yourproject.yourdataset.duplicates` 
              GROUP BY id)  
      

      注意:它假设 loadTime 也是唯一的 - 这意味着如果给定的 id 有多个具有最新 loadTime 的记录 - 它们都将被保留

      【讨论】:

        猜你喜欢
        • 2020-06-02
        • 1970-01-01
        • 1970-01-01
        • 2013-04-02
        • 1970-01-01
        • 2010-10-25
        • 2019-05-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多