PostgreSQL `IS NOT NULL` 对于复合类型无法正常工作

elB*_*rde 2 postgresql plpgsql composite-types sql-null

我正在尝试创建一个函数,该函数应该将表行映射到我的用户定义类型(这是复合类型)并返回结果。如果该表中的某些列为 NULL,则IS NOT NULL检查我的自定义类型不起作用!

例子

我有一个简单的复合类型:

CREATE TYPE my_custom_type AS (
  sender VARCHAR(30),
  destination VARCHAR(30),
  count INTEGER
);
Run Code Online (Sandbox Code Playgroud)

还有一张桌子:

CREATE TABLE messages (
  id INTEGER PRIMARY KEY,
  sender VARCHAR(30),
  destination VARCHAR(30),
  count INTEGER
);
Run Code Online (Sandbox Code Playgroud)

在此示例中插入单行:

INSERT INTO messages VALUES (1, 'sender', 'destination', 100);
Run Code Online (Sandbox Code Playgroud)

现在我想创建一个函数,它将将该行作为自定义 Postgres 类型返回:

CREATE OR REPLACE FUNCTION my_custom_function() 
RETURNS my_custom_type AS
$$
DECLARE
    result my_custom_type;
BEGIN

    SELECT sender, destination, count
    FROM messages
    LIMIT 1
    INTO result;

    IF result IS NULL THEN
        RAISE EXCEPTION 'no data';
    END IF;

    RETURN result;

END; $$
    LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

当我使用这个函数时,我得到了预期的结果:

SELECT * from my_custom_function();
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但是,当某些列更新为 NULL 时,就会开始出现意外行为:

UPDATE messages SET destination = NULL;
Run Code Online (Sandbox Code Playgroud)

当我再次执行该函数时,它仍然返回良好的结果: 在此输入图像描述

但是如果我将IS NULL条件更改为IS NOT NULL条件:

CREATE OR REPLACE FUNCTION my_custom_function() 
RETURNS my_custom_type AS
$$
DECLARE
    result my_custom_type;
BEGIN

    SELECT sender, destination, count
    FROM messages
    LIMIT 1
    INTO result;

    IF result IS NOT NULL THEN
        RETURN result;
    END IF;

    RAISE EXCEPTION 'no data';

END; $$
    LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

然后我得到一个错误: ERROR: no data

有人可以解释一下为什么这不起作用吗?对我来说完全是无稽之谈...

Lau*_*lbe 7

IS NULL如果所有元素都为 NULL,则为复合类型;IS NOT NULL如果所有元素都不为 NULL,则为复合类型。

\n

这是 SQL 标准所要求的。

\n

这会产生令人不快的后果,例如与复合类型x IS NOT NULL不同NOT x IS NULLTRUE此外,测试返回的两个值IS NULL可以不同:

\n
SELECT ROW(NULL, NULL) IS DISTINCT FROM NULL;\n\n ?column? \n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\n t\n(1 row)\n
Run Code Online (Sandbox Code Playgroud)\n

SQL 标准显然在这方面做得并不好。从 pgsql-hackers 列表中阅读此线程,以进一步启发混淆。

\n