从BigQuery表

时间:2016-04-17 10:47:31

标签: distinct google-bigquery

我有一个包含> 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);

6 个答案:

答案 0 :(得分:34)

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

应该有效的查询在这里:

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

答案 1 :(得分:18)

替代乔丹的答案 - 当副本太多时,这个答案会更好:

#standardSQL
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
)

答案 2 :(得分:5)

不确定为什么没人提到DISTINCT查询。

这是清除重复行的方法:

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

答案 3 :(得分:2)

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

答案 4 :(得分:1)

如果您的架构没有任何记录 - 在约旦的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设置为每行的相应Fixed_Accident_Index。 在这种情况下,BigQuery将删除重复的行

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

答案 5 :(得分:0)

Felipe's answer是大多数情况下的最佳方法。这是完成此操作的一种更优雅的方法:

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内存限制并遇到意外错误。