设置变量时,记录的IS NOT NULL测试不返回TRUE

时间:2014-02-13 20:50:19

标签: sql postgresql null row plpgsql

使用plpgsql过程提取记录(如果存在),如果存在,则使用它做一些事情。

变量是rowtype:

my_var my_table%rowtype;

我用SQL语句填充它:

select * from my_table where owner_id = 6 into my_var;

我知道它确实有一行:

raise notice 'my_var is %', my_var;

返回:

NOTICE:  my_var is (383,6,10)

但是现在我想测试一下,如果条件失败,它会记录下这些记录:

if my_var is null then
  raise notice 'IT IS NULL';
end if;
if my_var is not null then
  raise notice 'IT IS NOT NULL';
end if;

这些加注都没有出现在我的消息日志中 - 它只是从不进入块。如果您从SELECT * INTO收到了一行,那么测试的正确方法是什么?

1 个答案:

答案 0 :(得分:7)

我看到两个可能的原因,为什么......

  

这些加注都没有出现在我的消息日志中

未记录

首先,NOTICE通常不会使用默认设置写入数据库日志。我引用the manual here

  

log_min_messagesenum

     

控制将哪些消息级别写入服务器日志。有效值为DEBUG5DEBUG4DEBUG3DEBUG2DEBUG1INFONOTICEWARNINGERRORLOGFATALPANIC。 (...)
  默认值为警告。请注意,LOG的排名与client_min_messages中的排名不同。

大胆强调我的。另请注意NOTICE的不同默认值(client_min_messages)(手册中的上一项)。

测试无效

其次,考虑如何计算行表达式。如果(且仅当)每个元素row_variable IS NULL,则测试TRUE会返回NULL。给出以下示例:

SELECT (1, NULL) IS NULL AS a     -- FALSE
      ,(1, NULL) IS NOT NULL AS b -- also FALSE

两个表达式都返回FALSE。换句话说,行(或记录)变量(1, NULL)既不是NULL,也不是NOT NULL。因此,两个测试都失败了。

- > SQLfiddle with more details.

此相关答案中CHECK约束中此行为的更多详细信息,说明,链接和可能的应用:
NOT NULL constraint over a set of columns

您甚至可以使用NULL(rec := NULL)分配记录变量,这会导致每个元素都为NULL - 如果类型是众所周知的行类型。否则,我们正在处理匿名记录,结构未定义,您无法访问元素。但是,在您的示例中,rowtype之类的情况并非如此(这一直是众所周知的)。

解决方案:FOUND

  

如果您从SELECT * INTO收到了一行,那么测试的正确方法是什么?

您必须考虑该行可能为NULL,即使已分配。查询很可能返回了一堆NULL值(如果查询中的表定义允许NULL值)。这样的测试在设计上是不可靠的。

有一种简单而安全的方法。使用GET DIAGNOSTICS ...或(如果适用)特殊变量FOUND

SELECT * FROM my_table WHERE owner_id = 6 INTO my_var;

IF NOT FOUND THEN
   RAISE NOTICE 'Query did not return a row!';
END IF;

Details in the manual.