postgresql:附加的 WHERE 子句隐藏了行

postgresql: additional WHERE-clause hides rows

我的 SQL-请求加入 2 tables,结果是付款金额,按付款方式分组。 payment_history table 中存在付款方式:BlueMediaTransferuj、BankPaymentChangeSumpayment_history.payment_method 列也可以包含空字符串或 NULL - 在这种情况下,我想将其检索为 'other' 值。

SQL-查询是:

SELECT 
    CASE
        WHEN COALESCE(payment_history.payment_method, '') = '' THEN 'other'
        ELSE payment_history.payment_method
    END as payment_method, 
    CASE
        WHEN SUM(paid_balance) IS NULL THEN 0.00
        ELSE SUM(paid_balance)
    END as paid_balance, 
    CASE
        WHEN SUM(sum_without_commission) IS NULL THEN 0.00
        ELSE SUM(sum_without_commission)
    END as sum_without_commission                   
FROM 
    payment_history 
    LEFT JOIN 
    participants_list ON payment_history.registration_id = participants_list.registration_id 
WHERE 
    payment_history.client_id = 258 AND
    participants_list.deleted = 0 AND
    participants_list.is_reserved = 0
GROUP BY payment_history.payment_method

结果(没有支付方式Transferuj的记录,没关系,因为id= 258的当前客户不存在):

other 表示记录存在于 payment_history 中,其中 payment_methodNULL 或空字符串。

不想检索记录,支付方式是ChangeSum。所以,我在查询中添加了适当的条件:

...
WHERE payment_history.client_id = 258 
AND payment_history.payment_method != 'ChangeSum'
...

但在结果集中 other 也是空的:

为什么会出现这种情况,我该如何使用所需的方法获取数据(包括 other,当 payment_method 列包含 NULL|| 空字符串;但 没有 ChangeStatus)?

LEFT JOIN时,把右边的table条件放在ON子句中。 (在 WHERE 时,您将得到常规 INNER JOIN 结果。)

SELECT 
    CASE
        WHEN COALESCE(payment_history.payment_method, '') = '' THEN 'other'
        ELSE payment_history.payment_method
    END as payment_method, 
    CASE
        WHEN SUM(paid_balance) IS NULL THEN 0.00
        ELSE SUM(paid_balance)
    END as paid_balance, 
    CASE
        WHEN SUM(sum_without_commission) IS NULL THEN 0.00
        ELSE SUM(sum_without_commission)
    END as sum_without_commission                   
FROM payment_history 
LEFT JOIN participants_list 
ON payment_history.registration_id = participants_list.registration_id 
  AND participants_list.deleted = 0 
  AND participants_list.is_reserved = 0
WHERE payment_history.client_id = 258 
GROUP BY payment_history.payment_method

除了 jarlh 已解释的 left joinwhere 子句之外,您还可以使用 coalesce() 简化查询,并且可以在可为 null 的值周围使用 coalesce()用于比较,因此它们不会 return null.

select 
    coalesce(payment_history.payment_method, 'other') as payment_method
  , coalesce(sum(paid_balance),0.00) as paid_balance
  , coalesce(sum(sum_without_commission),0.00) as sum_without_commission
from payment_history 
  left join participants_list 
    on payment_history.registration_id = participants_list.registration_id 
   and participants_list.deleted = 0 
   and participants_list.is_reserved = 0
where payment_history.client_id = 258 
  and coalesce(payment_history.payment_method,'')!='ChangeSum'
group by payment_history.payment_method

当比较payment_method为null时,null != 'ChangeSum'将returnnull,不成立。 Comparison Operators

扩展 null 比较问题:

Null 被视为 unknown,因此与 null 的比较始终是 unknown,因此如果您过滤 null != 'ChangeSum',结果不是 true(即 null),而您的 where 仅包含您的条件为 true 的结果。 https://www.postgresql.org/docs/9.1/static/functions-comparison.html

payment_methodnull 时使用 coalesce(payment_history.payment_method,'')!='ChangeSum' returns true,因为 coalesce 正在替换 null 值与 '' 进行比较, '' != 'ChangeSum'true.

感谢@SqlZim 和@jarlh,我更改了我的查询。以下是有效变体:

SELECT 
COALESCE(NULLIF(payment_history.payment_method, ''), 'other') AS payment_method, 
COALESCE(SUM(paid_balance), 0.00) AS paid_balance,
COALESCE(SUM(sum_without_commission), 0.00) AS sum_without_commission                  
FROM payment_history 
INNER JOIN participants_list 
ON payment_history.registration_id = participants_list.registration_id 
WHERE payment_history.client_id = 258 
AND participants_list.deleted = 0 
AND participants_list.is_reserved = 0
AND COALESCE(payment_history.payment_method, '') != 'ChangeSum'
GROUP BY payment_history.payment_method

也可以写成

AND payment_history.payment_method IS DISTINCT FROM 'ChangeSum'

而不是

AND COALESCE(payment_history.payment_method, '') != 'ChangeSum'

,正如@Clodoaldo Neto 所建议的那样。

使用is distinct from:

and payment_history.payment_method is distinct from 'ChangeSum'