-- 保留每个 order_id 中 order_time 最新的一条
SELECT
order_id,
customer_id,
amount,
order_time
FROM orders_with_dupes
WINDOW w AS (PARTITION BY order_id ORDER BY order_time DESC)
QUALIFY ROW_NUMBER() OVER w = 1;
结果说明:
order_id
customer_id
amount
order_time
O001
101
100
2024-06-01 10:00:00
O002
102
200
2024-06-01 11:05:00
O003
103
300
2024-06-01 12:00:00
语法优势
使用
QUALIFY
QUALIFY
可以避免嵌套子查询,SQL 更易读:
-- ❌ 传统写法(子查询嵌套)
SELECT order_id, customer_id, amount, order_time
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY order_time DESC) as rn
FROM orders_with_dupes
) t
WHERE rn = 1;
-- ✅ Lakehouse 推荐写法(QUALIFY)
SELECT order_id, customer_id, amount, order_time
FROM orders_with_dupes
QUALIFY ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY order_time DESC) = 1;
基于多字段组合去重
当重复数据仅部分字段不同(如时间戳不同),且你只需要保留关键字段时,可以使用
GROUP BY
GROUP BY
配合聚合函数。
-- 按 order_id 分组,保留最大金额和最新时间
SELECT
order_id,
customer_id,
MAX(amount) as max_amount,
MAX(order_time) as latest_time
FROM orders_with_dupes
GROUP BY order_id, customer_id;
适用场景:
只需要统计维度数据,不关心具体是哪一条记录。
数据量极大,窗口函数性能不如聚合函数时。
物理去重(重写表)
查询去重只是逻辑上去重,如果需要物理清理重复数据,可以将去重结果写回原表或新表。
方案 1:写入新表(推荐)
-- 创建去重后的新表
CREATE TABLE orders_deduped AS
SELECT *
FROM orders_with_dupes
QUALIFY ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY order_time DESC) = 1;
方案 2:覆盖原表
-- 覆盖原表数据(谨慎操作)
INSERT OVERWRITE TABLE orders_with_dupes
SELECT *
FROM orders_with_dupes
QUALIFY ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY order_time DESC) = 1;
清理测试数据
完成去重验证后,建议清理测试表,避免占用存储空间:
-- 删除测试表
DROP TABLE IF EXISTS orders_with_dupes;
DROP TABLE IF EXISTS orders_deduped;