Teradata中获取每行多列唯一值,除CASE语句外还有其他方法吗?
在Teradata中提取每行多列的唯一值并重新排列(填充NULL)
问题背景
现有Teradata表结构及数据如下:
COL1 | COL2 | COL3 | COL4 -------------------------- 1 | 1 | 2 | 3 2 | 2 | 2 | 4 4 | 5 | 6 | 7
需要实现:提取每行中所有列的唯一值,去除重复后按顺序排列到原列位置,多余位置填充NULL,期望结果如下:
COL1 | COL2 | COL3 | COL4 -------------------------- 1 | 2 | 3 | NULL 2 | 4 | NULL | NULL 4 | 5 | 6 | 7
目前已通过逐列对比的CASE语句实现,但希望找到更简洁、可扩展性更强的方法。
更优实现方法:UNPIVOT + 去重 + ROW_NUMBER + PIVOT
这种方法无需硬编码列间对比逻辑,当列数变化时只需调整少量代码,灵活性更高。
步骤说明
- 生成行唯一标识:如果表没有主键,用
ROW_NUMBER()为每行生成唯一ID用于后续分组;若有主键则直接使用主键。 - UNPIVOT转置:将每行的多列数据转成多行(每行对应一个列值),保留行标识。
- 去重并编号:对同一行下的列值去重,然后用
ROW_NUMBER()为每个唯一值分配序号。 - PIVOT转回列:按序号将行数据转回列,序号超出唯一值数量的位置自动填充
NULL。
完整SQL示例
假设表名为test_table:
WITH row_identifier AS ( -- 生成每行的唯一ID,若表有主键可替换为主键列 SELECT ROW_NUMBER() OVER(ORDER BY COL1, COL2, COL3, COL4) AS row_id, COL1, COL2, COL3, COL4 FROM test_table ), unpivoted_data AS ( -- 转置列行为行数据 SELECT row_id, col_value FROM row_identifier UNPIVOT ( col_value FOR col_name IN (COL1, COL2, COL3, COL4) ) AS unpvt ), deduplicated_ranked AS ( -- 去重并为每个唯一值分配序号 SELECT row_id, col_value, ROW_NUMBER() OVER(PARTITION BY row_id ORDER BY col_value) AS rank_num FROM unpivoted_data GROUP BY row_id, col_value ) -- 转回列结构 SELECT MAX(CASE WHEN rank_num = 1 THEN col_value END) AS COL1, MAX(CASE WHEN rank_num = 2 THEN col_value END) AS COL2, MAX(CASE WHEN rank_num = 3 THEN col_value END) AS COL3, MAX(CASE WHEN rank_num = 4 THEN col_value END) AS COL4 FROM deduplicated_ranked GROUP BY row_id ORDER BY row_id;
补充说明
- 若表存在主键(比如
id列),可直接替换row_identifier中的ROW_NUMBER()部分,避免因排序导致的性能损耗。 - 当列数增加时,只需修改
UNPIVOT中的列列表,以及最后SELECT中的CASE分支数量,无需调整大量对比逻辑,比CASE语句更易维护。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

