优化具有不同值的列的查询,包括。空

问题描述 投票:0回答:1
身份证 金额 品牌
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 与任何值视为不同。

此解决方案是否有更好或更快的查询?喜欢横向连接或窗口函数吗?

sql postgresql postgresql-performance
1个回答
2
投票

在桌子上单次通过应该会快很多:

SELECT id, col
FROM  (
   SELECT id
        , min(amount) <> max(amount) AS a_diff, bool_or(true) FILTER (WHERE amount IS NULL) AS a_null
        , min(brand)  <> max(brand)  AS b_diff, bool_or(true) FILTER (WHERE brand  IS NULL) AS b_null
   FROM   tbl
   GROUP  BY id
   ) t
JOIN   LATERAL (
   VALUES
     ('Amount', a_diff, a_null)
   , ('Brand' , b_diff, b_null)
   ) x(col, diff, has_null) ON (diff OR NOT diff AND has_null)
ORDER  BY id, col

小提琴

另外,

count(DISTINCT ...)
是出了名的昂贵。我们实际上并不需要那个计数。我们只需要知道最小值是否与最大值不同(或不同,但至少还有一个
NULL
)。

非常相似的案例,有更多解释:

看起来您已经看过那个,但尚未应用于您的案例。
就像我在那里提到的:对于每组many行有更快的方法......

© www.soinside.com 2019 - 2024. All rights reserved.