与...不同

来自 PostgreSQL Wiki
跳转到导航跳转到搜索

Pg 支持两种比较语句 **IS DISTINCT FROM** 和 **IS NOT DISTINCT FROM**,它们本质上将 NULL 视为一个已知的值,而不是一个表示 _未知_ 的特殊情况。

助记符: _DISTINCT 意为不同,这就是 '<>' 测试的内容_

语法

SELECT foo,bar FROM table WHERE foo IS DISTINCT FROM bar;
SELECT foo,bar FROM table WHERE foo IS NOT DISTINCT FROM bar;

真值表

\pset null '<<NULL>>'

select a.a, b.b, a.a IS DISTINCT FROM b.b AS "Is Distinct From" FROM (VALUES (1), (2), (NULL)) AS a (a), (VALUES (1), (2), (NULL)) AS b (b);

    a     |    b     | Is Distinct From 
----------+----------+------------------
        1 |        1 | f
        1 |        2 | t
        1 | <<NULL>> | t
        2 |        1 | t
        2 |        2 | f
        2 | <<NULL>> | t
 <<NULL>> |        1 | t
 <<NULL>> |        2 | t
 <<NULL>> | <<NULL>> | f

select a.a, b.b, a.a IS NOT DISTINCT FROM b.b AS "Is Not Distinct From" FROM (VALUES (1), (2), (NULL)) AS a (a), (VALUES (1), (2), (NULL)) AS b (b);

    a     |    b     | Is Not Distinct From 
----------+----------+----------------------
        1 |        1 | t
        1 |        2 | f
        1 | <<NULL>> | f
        2 |        1 | f
        2 |        2 | t
        2 | <<NULL>> | f
 <<NULL>> |        1 | f
 <<NULL>> |        2 | f
 <<NULL>> | <<NULL>> | t

使用 CASE 语句编写

这两个 SQL 比较宏都可以使用CASE语句

foo IS NOT DISTINCT FROM bar

CASE
  -- Act like a normal '=' on non-null values.
  WHEN foo IS NOT NULL AND bar IS NOT NULL
    THEN foo = bar
  -- foo = 'notnull' , bar = 'null' ; then foo <> bar so false
  WHEN foo IS NOT NULL AND bar IS NULL
    THEN false
  -- foo = 'null' , bar = 'null' ; then foo = bar so true
  WHEN foo IS NULL AND bar IS NULL
    THEN true
  ELSE false
END

foo IS DISTINCT FROM bar

CASE
  -- Act like a normal '<>' on non-null values.
  WHEN foo IS NOT NULL AND bar IS NOT NULL
    THEN foo <> bar
  -- foo = 'notnull' , bar = 'null' ; then foo <> bar so true
  WHEN foo IS NOT NULL AND bar IS NULL
    THEN true
  -- foo = 'null' , bar = 'null' ; then foo = bar so false
  WHEN foo IS NULL AND bar IS NULL
    THEN false
  ELSE true
END

确定表中的不同数据

假设你有两个表,t1t2,它们都有以下列"foo","bar","baz"并且你想查看 t1 中所有不在 t2 中的行。通常,如果你想要 '=' 的效果,你可以非常简单地做到这一点

SELECT foo,bar,baz
FROM t1
LEFT OUTER JOIN t2 USING (foo,bar,baz)
WHERE t1.foo IS NULL

USING (foo,bar,baz) 仅仅是以下内容的宏:t1.foo = t2.foo AND t1.bar = t2.bar AND t1.baz = t2.baz

但是,如果你想要将 null 视为已知值的替代方案,你将需要IS NOT DISTINCT FROM。在连接表时,任务会变得稍微冗长和令人生畏,因为没有IS NOT DISTINCT FROM形式的简写。

SELECT t1.foo,t1.bar,t1.baz
FROM t1
LEFT OUTER JOIN t2 ON (
 t1.foo IS NOT DISTINCT FROM t2.foo
 AND t1.bar IS NOT DISTINCT FROM t2.bar
 AND t1.baz IS NOT DISTINCT FROM t2.baz
)
WHERE ( t2.foo IS NULL )