Sql 如何在BigQuery中按时间戳删除重复的行?

Sql 如何在BigQuery中按时间戳删除重复的行?,sql,google-bigquery,Sql,Google Bigquery,我有一个具有以下架构的products表: id createdOn, updatedOn, stock, status createdOn和updatedOn是时间戳 createdOn是分隔字段 假设这是我现在掌握的数据: id createdOn, updatedOn, stock, status 1 2018-09-14 14:14:24.305676 2018-09-14 14:14:24.305676

我有一个具有以下架构的products表:

id  createdOn, updatedOn, stock, status
createdOn
updatedOn
时间戳

createdOn
是分隔字段

假设这是我现在掌握的数据:

id  createdOn,                    updatedOn,                stock, status
1   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  10    5
2   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  5     12
3   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  10     5
我有一个
ETL
,它将新行追加到此表中。当ETL完成时,我可能会遇到相同的
id
有多行的情况

例如:

id  createdOn,                    updatedOn,                stock, status
1   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  10    5
2   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  5     12
3   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  10     5
1   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  10     5
3   2018-09-14 14:14:24.305676   2018-09-15 10:00:00.000000  7     5
我希望有一个查询,它将在表上运行,并确保每个id只有一行-带有
MAX(updatedOn)
的行应该保留。每个id的
MAX(updatedOn)
可以有多行-在这种情况下,可以保证它们是相同的,因为如果它们不是相同的,那么
updatedOn
字段就会被修改

重新调整查询后,表将如下所示:

id  createdOn,                    updatedOn,                stock, status
2   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  5     12
1   2018-09-14 14:14:24.305676   2018-09-14 14:14:24.305676  10     5
3   2018-09-14 14:14:24.305676   2018-09-15 10:00:00.000000  7     5
如何编写一个有效执行此操作的查询

我知道应该是这样的:

DELETE FROM products
WHERE id NOT IN
(
    SELECT MAX(id)
    FROM products
    GROUP BY id
)
然而,这是行不通的。。。我没有自动递增字段来区分行


如何解决此问题?

使用
行数
函数

DELETE FROM products
WHERE STRUCT(id,createdOn,stock) IN (
        select id,createdOn,stock from
        (SELECT id,createdOn,stock,
          ROW_NUMBER()
                  OVER (PARTITION BY createdOn,stock,updatedOn order by id) as rn from products
                  ) t where rn>1
         ) 
另一种方法是,您可以按照“删除”替换表

CREATE OR REPLACE TABLE products AS
SELECT * EXCEPT(rn)
FROM (
  SELECT *, ROW_NUMBER() OVER(PARTITION BY createdOn,stock,updatedOn order by id) rn
  FROM products
) 
WHERE rn> 1 

使用
行号
功能

DELETE FROM products
WHERE STRUCT(id,createdOn,stock) IN (
        select id,createdOn,stock from
        (SELECT id,createdOn,stock,
          ROW_NUMBER()
                  OVER (PARTITION BY createdOn,stock,updatedOn order by id) as rn from products
                  ) t where rn>1
         ) 
另一种方法是,您可以按照“删除”替换表

CREATE OR REPLACE TABLE products AS
SELECT * EXCEPT(rn)
FROM (
  SELECT *, ROW_NUMBER() OVER(PARTITION BY createdOn,stock,updatedOn order by id) rn
  FROM products
) 
WHERE rn> 1 

我强烈建议您只创建一个新表:

create table correct_table as
    select distinct id, createdOn, updatedOn
    from etl_table;
BigQuery的优势在于处理数据。当需要更新或删除时,我尝试寻找其他解决方案(例如复制表)


您可能需要重新思考您的处理过程。只需让ETL加载一个包含新行的表。然后使用BigQuery插入不存在的新行。换句话说,插入行然后删除它们不是一种方法。

我强烈建议您只创建一个新表:

create table correct_table as
    select distinct id, createdOn, updatedOn
    from etl_table;
BigQuery的优势在于处理数据。当需要更新或删除时,我尝试寻找其他解决方案(例如复制表)


您可能需要重新思考您的处理过程。只需让ETL加载一个包含新行的表。然后使用BigQuery插入不存在的新行。换句话说,插入行然后删除它们不是一种方法。

我认为Gordon Linoff是对的,BigQuery用例不是一直操作数据和更新现有行

无论如何,此查询将只返回所需的行:

SELECT DISTINCT id, createdOn,  updatedOn,  stock,  status
FROM `project.dataset.maxtimestamp` AS t1
INNER JOIN (SELECT id AS i2, MAX(updatedOn) AS up
FROM `project.dataset.maxtimestamp`
GROUP BY id) AS t2
ON t1.id = t2.i2 AND t1.updatedOn = t2.up
还有你已经找到的这个:

SELECT id,  createdOn,  updatedOn,  stock,  status
FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY createdOn, id ORDER BY updatedOn desc) AS rn
       FROM `training-wave-12-vmarin.asdf.duplicated_timestamp` AS t2)
WHERE rn>1

无论如何,我不确定它有多优化…

我认为Gordon Linoff是对的,BigQuery用例不是一直操作数据和更新现有行

无论如何,此查询将只返回所需的行:

SELECT DISTINCT id, createdOn,  updatedOn,  stock,  status
FROM `project.dataset.maxtimestamp` AS t1
INNER JOIN (SELECT id AS i2, MAX(updatedOn) AS up
FROM `project.dataset.maxtimestamp`
GROUP BY id) AS t2
ON t1.id = t2.i2 AND t1.updatedOn = t2.up
还有你已经找到的这个:

SELECT id,  createdOn,  updatedOn,  stock,  status
FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY createdOn, id ORDER BY updatedOn desc) AS rn
       FROM `training-wave-12-vmarin.asdf.duplicated_timestamp` AS t2)
WHERE rn>1

无论如何,不确定它的优化程度…

语法错误:在[6:15]处出现意外标识符“行号”@Programmer120请参见now@Pentium10为什么我需要选择*?这会带来不必要的列。。这在BigQuery中需要花钱。分区不是应该按id顺序更新吗?您建议的分区语法更好,除非您不返回任何内容,否则select*不是问题,在delete语法中没有成本问题。@Pentium10但您确实返回了。。。查询将完全执行,然后才执行删除。语法错误:在[6:15]处出现意外标识符“row_number”@Programmer120请参阅now@Pentium10为什么我需要选择*?这会带来不必要的列。。这在BigQuery中需要花钱。分区不是应该按id顺序更新吗?您建议的分区语法更好,除非您不返回任何内容,否则select*不是问题,在delete语法中没有成本问题。@Pentium10但您确实返回了。。。完全执行查询,然后才执行删除。我不知道这将如何工作。“旧表”可以包含不在我正在运行的ETL中的行。我实际上想做的是某种升级的解决方案。我可以创建一个WIP表并对其进行处理,当完成从该表到生产表的写截短操作时,仍然需要执行删除或更新。。没有保存任何内容。@Programmer120。您不需要执行
delete
s或
update
s,或者至少我还不需要在我在BigQuery中实现的系统上执行这些操作。但这不是你在这里问的问题。我只是提供了一个超出问题范围的解决方案。我提供的答案是创建一个新表,而不是从旧表中删除(使用
选择distinct
,但是如果您有问题中未提到的其他列,您可能需要稍微不同的逻辑)。我知道你把它带出了范围。。没关系,我只是不明白你的逻辑。您建议运行ETL,然后仅从旧表复制不存在的id。这仍然需要逐行传递。请记住,我的分区位于createdate上,但在这里不参与。我不知道这将如何工作。“旧表”可以包含不在我正在运行的ETL中的行。我实际上想做的是某种升级的解决方案。我可以创建一个WIP表并对其进行处理,当完成从该表到生产表的写截短操作时,仍然需要执行删除或更新。。没有保存任何内容。@Programmer120。您不需要执行
delete
s或
update
s,或者至少我还不需要在我在BigQuery中实现的系统上执行这些操作。但这不是你在这里问的问题。我只是提供了一个超出问题范围的解决方案。我提供的答案是创建一个新表,而不是从旧表中删除(使用
选择distinct
),但如果您有问题中未提到的其他列,则可能需要sl