IS NOT DISTINCT FROM vs row-wise equality with =
-
09-01-2021 - |
Вопрос
Looking at the below query,
SELECT null IS NOT DISTINCT FROM null AS indf,
null = null AS eq;
indf | eq
------+----
t |
From this we can see the result of the IS NOT DISTINCT FROM
is true
, and the result of the eq
is false
. The following then logically follows from that,
-- 1 rows
SELECT *
FROM ( VALUES (null) ) AS t(a)
JOIN ( VALUES (null) ) AS g(a)
ON t.a IS NOT DISTINCT FROM g.a;
-- 0 rows
SELECT *
FROM ( VALUES (null) ) AS t(a)
JOIN ( VALUES (null) ) AS g(a)
ON t.a = g.a;
Because if the condition returns null
the join
fails. But, this throws me off, with row-wise comparison
-- returns 1 row.
SELECT *
FROM ( VALUES (null) ) AS t(a)
JOIN ( VALUES (null) ) AS g(a)
ON (t) IS NOT DISTINCT FROM (g);
-- also returns one row.
SELECT * FROM ( VALUES (null) ) AS t(a)
JOIN ( VALUES (null) ) AS g(a)
ON (t) = (g);
Why does row-wise comparison treat null
s different than scalar comparison? And is there a point of IS NOT DISTINCT FROM
in row-wise comparison?
Решение
This behavior is documented under Composite Type Comparison,
The SQL specification requires row-wise comparison to return NULL if the result depends on comparing two
NULL
values or aNULL
and a non-NULL
. PostgreSQL does this only when comparing the results of two row constructors (as in Section 9.23.5) or comparing a row constructor to the output of a subquery (as in Section 9.22). In other contexts where two composite-type values are compared, twoNULL
field values are considered equal, and aNULL
is considered larger than a non-NULL
. This is necessary in order to have consistent sorting and indexing behavior for composite types.
This essentially means that the standard behavior can only be seen in the following syntax (ROW()
is the row-constructor):
SELECT * FROM ( VALUES (null) ) AS t(a)
JOIN ( VALUES (null) ) AS g(a)
ON ROW(t.*) = ROW(g.*);
versus,
SELECT * FROM ( VALUES (null) ) AS t(a)
JOIN ( VALUES (null) ) AS g(a)
ON ROW(t.*) IS NOT DISTINCT FROM ROW(g.*);
Just using the ROW constructor with the type will not work either ON ROW(t) = ROW(g)