从PostgreSQL函数返回NULL而不是复合值

时间:2017-03-06 16:45:28

标签: postgresql

让我们在PostgreSQL中有以下内容:

CREATE TYPE struct AS (x INT, y INT);
CREATE TABLE tbl (a INT, b struct);

CREATE FUNCTION find_tbl_entry(clear BOOL) RETURNS tbl AS $$
DECLARE k tbl;
BEGIN
  IF clear THEN
    k.b := NULL;
  END IF;

  RETURN k;
END;
$$ LANGUAGE plpgsql;

也就是说,我们有一个函数返回复合类型tbl的值,而复合类型b的值又是复合类型struct的属性SELECT find_tbl_entry(FALSE)作为其属性之一。 (原始问题更有趣 - 翻译函数返回一行,其中一些属性相应地翻译;但问题归结为所呈现的代码。)

(,(,))导致a,即NULL b和空结构(NULL和NULL对)作为SELECT find_tbl_entry(TRUE)的值,有点期待。

现在,即使(,(,))导致b,即使NULL属性明确设置为NULL,结果也不是find_tbl_entry,但它仍然是空结构。

我可以为NULL函数在b属性中返回k.b := NULL做些什么?

编辑:事实证明,奇怪的是作业k.b := NULL; RAISE NOTICE '%', k.b IS DISTINCT FROM NULL; 。扩展功能时:

NULL

它发出“NOTICE:t”。因此,似乎将NULL分配给复合值实际上会分配具有所有属性NULL的复合。考虑到(NULL,NULL)值与UPDATE tbl SET b = NULL存储在一个表中时b IS NOT DISTINCT FROM NULL可以区分这一事实,这是非常奇怪的事实(UPDATE tbl SET b = (NULL,NULL)会导致每行保留false;另一方面,- parent -- sub0 --- 0.pgm --- 1.pgm --- ... -- sub1 --- 0.pgm --- 1.pgm --- ... -- ... 对于该测试是parent

2 个答案:

答案 0 :(得分:1)

在SQL中,当所有组件都是NULL时,复合值(SQL标准将其称为“度数值> 1”)为NULL,因此PostgreSQL的行为正确。

ISO / IEC 9075-2:2003,第8章,第7节,说:

  

8.7< null谓词>

     

<强>功能

     

指定空值的测试。

     

<强>格式

<null predicate> ::= <row value predicand> <null predicate part 2>
<null predicate part 2> ::= IS [ NOT ] NULL
     

语法规则

     

无。

     

访问规则

     

无。

     

一般规则

     

1)让 R 为&lt;行值谓词&gt;的值。

     

2)案例:

     

a)如果 R 为空值,则“R IS NULL”为 True

     

b)否则:

     

i)“R IS NULL”的值是

     

案例:

     

1)如果 R 中每个字段的值都为空值,则 True

     

2)否则, False

     

ii)“R IS NOT NULL”的值是

     

案例:

     

1)如果 R 中无字段的值为空值,则 True

     

2)否则, False

(如果您认为这很疯狂,那么您并不孤单。)

您可以验证PostgreSQL是否正确处理了这样的值:

SELECT (ROW(NULL,ROW(NULL,NULL))::tbl).b IS NULL;
 ?column?
----------
 t
(1 row)

我理解你更喜欢读取(NULL, NULL)的值,但是你不能用PostgreSQL来获得它。我希望对你来说这是一种安慰,它仍会表现得正确。

答案 1 :(得分:1)

有必要:

直接返回null而不是返回指定的变量:

create or replace function find_tbl_entry()
returns tbl as $$
declare s struct;
begin
    s := null;
    return (1, nullif(s, (null,null)::struct));
end;
$$ language plpgsql;

select a, b, b is null from find_tbl_entry();
 a | b | ?column? 
---+---+----------
 1 |   | t

或者在功能使用时间进行比较:

select coalesce(nullif((find_tbl_entry()).b, (null,null)::struct), (1,2)::struct);
 coalesce 
----------
 (1,2)