身份证 | 金额 | 品牌 |
---|---|---|
1 | 10 | 空 |
1 | 20 | 空 |
2 | 30 | 马扎达 |
2 | 空 | 宝马 |
3 | 40 | 空 |
3 | 40 | 起亚 |
4 | 空 | 本田 |
4 | 空 | 本田 |
上面是原始表格,我的目标是找出每列相同 ID 内的任何差异。
在同一个ID组中,如果列有差异,则创建一个新列,然后指定哪一列有差异。
结果应该是这样的
身份证 | 差异 |
---|---|
1 | 金额 |
2 | 金额 |
2 | 品牌 |
3 | 品牌 |
我的 PostgreSQL 代码
SELECT
ID,
'Amount' AS Difference
FROM
table
GROUP BY
ID
HAVING
COUNT(DISTINCT amount) > 1
OR (COUNT(amount) != COUNT(*) AND COUNT(DISTINCT amount) > 0)
UNION ALL
SELECT
ID,
'Brand' AS Difference
FROM
table
GROUP BY
ID
HAVING
COUNT(DISTINCT brand) > 1
OR (COUNT(brand) != COUNT(*) AND COUNT(DISTINCT brand) > 0)
注意记录中存在NULL值,这样聚合函数就不会统计NULL值。 NULL 与 NULL 视为相同,但 NULL 与任何值视为不同。
此解决方案是否有更好或更快的查询?像横向连接或窗口函数?谢谢
计算不同值(包括空值)很容易。如果至少有一个空值,则在非重复计数中加 1。话虽这么说,您的查询可以如下所示,从而更容易扩展多列而不进行联合:
with cte as (
select id
, count(distinct amount) + max(case when amount is null then 1 else 0 end) > 1 as a_is_different
, count(distinct brand) + max(case when brand is null then 1 else 0 end) > 1 as b_is_different
from t
group by id
)
select id, column_name
from cte, lateral (values
('amount', a_is_different),
('brand', b_is_different)
) as v(column_name, is_different)
where is_different