我遇到了一个困难,因为在比较子查询中的两个字段时,虽然字段相同,即它们都具有NULL值,但比较返回FALSE结果
Therfore NULL = NULL返回FALSE
现在我知道NULL应该与IS运算符进行比较,但是当我比较两个字段时,我应该知道它们是否包含空值?如果值为NULL,我需要比较两个相同数据的字段。
考虑这个SQL:
SELECT
*
FROM
fts.fts_customers_data_50360001
WHERE
fts.fts_customers_data_50360001.record_type = 15
AND
fts.fts_customers_data_50360001.mid = 103650360001
AND NOT EXISTS
(
SELECT
fts.temp_fees_50360001.record_type
FROM
fts.temp_fees_50360001
WHERE
fts.temp_fees_50360001.record_type = fts.fts_customers_data_50360001.record_type
AND
fts.temp_fees_50360001.merch_id = fts.fts_customers_data_50360001.mid
AND
fts.temp_fees_50360001.fee_curr = fts.fts_customers_data_50360001.currency
AND
fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
AND
fts.temp_fees_50360001.tran_type = fts.fts_customers_data_50360001.fee_type
AND
fts.temp_fees_50360001.area = fts.fts_customers_data_50360001.region
AND
fts.temp_fees_50360001.srvc_type = fts.fts_customers_data_50360001.card_type
);
在上面的查询中,
fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
内部都有NULL值,但比较返回false ..太糟糕了
任何想法都会得到很多赞赏
答案 0 :(得分:6)
正如其他人所指出的那样,NULL
无法与NULL
进行比较。
在Postgres中,您可以使用运算符IS DISTINCT FROM
缩短表达式,<>
是IS NOT DISTINCT FROM
的空值安全替代品。在您的情况下,您需要使用IS EQUAL TO
来比较相等性(看起来有点错误的方法,但不幸的是,SQL标准中没有定义相应的(fts.temp_fees_50360001.record_type = fts.fts_customers_data_50360001.record_type
OR (fts.temp_fees_50360001.record_type IS NULL
AND fts.fts_customers_data_50360001.record_type IS NULL)
)
。
当任一输入为空时,普通比较运算符产生null(表示“未知”),而不是true或false。例如,7 = NULL产生null,7&lt;&gt;空值。如果此行为不合适,请使用IS [NOT] DISTINCT FROM构造:
所以,而不是
(fts.temp_fees_50360001.record_type IS NOT DISTINCT FROM fts.fts_customers_data_50360001.record_type)
你可以使用:
{{1}}
自动处理NULL值。如果你想比较相等但是它仍然很短,那么这个条件看起来有点奇怪。
答案 1 :(得分:4)
首先,为表使用别名,您的查询将更具可读性:
select *
from fts.fts_customers_data_50360001 as d
where
d.record_type = 15 and
d.mid = 103650360001 and
not exists
(
select *
from fts.temp_fees_50360001 as f
where
f.record_type = d.record_type and
f.merch_id = d.mid and
f.fee_curr = d.currency and
f.card_scheme = d.card_scheme and
f.tran_type = d.fee_type and
f.area = d.region and
f.srvc_type = d.card_type
)
至于你的问题,有几种方法可以做到这一点,例如,你可以使用这样的语法:
...
(
f.card_scheme is null and d.card_scheme is null or
f.card_scheme = d.card_scheme
)
...
或者使用coalesce
一些无法存储在您的列中的值:
...
coalesce(f.card_scheme, -1) = coalesce(d.card_scheme, -1)
...
最近我也喜欢将exists
与intersect
一起用于此类比较:
...
exists (select f.card_scheme, f.tran_type intersect select d.card_scheme, d.tran_type)
...
只是旁注 - 在编写此类查询时必须小心,并检查查询计划以确保使用索引。
答案 2 :(得分:1)
在SQL中,null
永远不会等于null
。获得与null进行比较的真实结果的唯一方法是通过特殊测试:
IS NULL
IS NOT NULL
在您的情况下,您必须专门为&#34;两个空值&#34;案件被认为是平等的:
AND (fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
OR (fts.temp_fees_50360001.card_scheme IS NULL
AND fts.fts_customers_data_50360001.card_scheme IS NULL)
)
没有处理它(虽然有一些变化)。
答案 3 :(得分:0)
以下内部SELECT工作(但我不保证性能):
SELECT
fts.temp_fees_50360001.record_type
FROM
fts.temp_fees_50360001
WHERE
(fts.temp_fees_50360001.record_type = fts.fts_customers_data_50360001.record_type
OR (fts.temp_fees_50360001.record_type IS NULL AND fts.fts_customers_data_50360001.record_type IS NULL))
AND
(fts.temp_fees_50360001.merch_id = fts.fts_customers_data_50360001.mid
OR (fts.temp_fees_50360001.merch_id IS NULL AND fts.fts_customers_data_50360001.mid IS NULL))
AND
(fts.temp_fees_50360001.fee_curr = fts.fts_customers_data_50360001.currency
OR (fts.temp_fees_50360001.fee_curr IS NULL AND fts.fts_customers_data_50360001.currency IS NULL))
AND
(fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
OR (fts.temp_fees_50360001.card_scheme IS NULL AND fts.fts_customers_data_50360001.card_scheme IS NULL))
AND
(fts.temp_fees_50360001.tran_type = fts.fts_customers_data_50360001.fee_type
OR (fts.temp_fees_50360001.tran_type IS NULL AND fts.fts_customers_data_50360001.fee_type IS NULL))
AND
(fts.temp_fees_50360001.area = fts.fts_customers_data_50360001.region
OR (fts.temp_fees_50360001.area IS NULL AND fts.fts_customers_data_50360001.region IS NULL))
AND
(fts.temp_fees_50360001.srvc_type = fts.fts_customers_data_50360001.card_type
OR (fts.temp_fees_50360001.srvc_type IS NULL AND fts.fts_customers_data_50360001.card_type))