案例再现
某日,写一份关于判断是不是已经报名过的存储过程, 代码如下:
--变量定义区,定义一个row type等下暂时存储数据
declare rowType_order_signed_up "pt_order"%rowType;
declare enum_orderStatus "PartyOrderStatusEnumObj";
--这是存储过程正文
--思路:获取符合条件的订单记录到rowType_order_signed_up然后判断是否有这条记录,如果有的话就表示用户已经报名了.提示报名,没有的话就可以报名
--查看一下报名数据,自己是不是已经报名了。
select * into rowType_order_signed_up from pt_order
where "partyId" = rv_partyId and "userId" = rv_visitUserId
and "payStatus" = 1
and status = ANY(ARRAY[
"getCodeFromEnumItem"(enum_orderStatus."hasJoined")
,
"getCodeFromEnumItem"(enum_orderStatus."Wait4Audit")
,"getCodeFromEnumItem"(enum_orderStatus."Finish")
,"getCodeFromEnumItem"(enum_orderStatus."Expired")
])
;
if rowType_order_signed_up is not null then
raise notice '看到这里就可以明白,系统没有将rowType 判断为null';
end if;
if rowType_order_signed_up is null then
--报名过的。
if rowType_order_signed_up.status="getCodeFromEnumItem"(enum_orderStatus."Wait4Audit") then
op_result:="webTools_opResult"(false,0,
'亲~您已经报名过该活动,系统已经通知活动发起人及时审核通过您的报名申请,请耐心等候。'
);
return;
end if;
if rowType_order_signed_up.status="getCodeFromEnumItem"(enum_orderStatus."hasJoined") then
op_result:="webTools_opResult"(false,0,'亲~您已经成功报名了,请不要重复报名。');
return;
end if;
if rowType_order_signed_up.status="getCodeFromEnumItem"(enum_orderStatus."Finish") then
op_result:="webTools_opResult"(false,0,'亲~您已经完成活动了,不能再次报名哦。');
return;
end if;
op_result:="webTools_opResult"(false,0,'亲~您已经报名了,请勿重复报名');
return;
end if;
然后发现,在实际运行过程中,无论如何执行,rowType的is not null判断返回的都是false,在数据表一看,
这个小老弟都已经没了十张票了,真有趣.
然后一查文档…
坑爹啊
官方说明
提示: 有些应用可能要求表达式expression = NULL 在expression为 NULL 时候返回真。 我们强烈建议这样的应用修改成遵循 SQL 标准。但是,如果这样修改是不可能的, 那么我们可以打开transform_null_equals配置参数, 让PostgreSQL将x = NULL 自动转换成x IS NULL。
注意: 如果expression是行值, 那么当行表达式本身为 NULL 或该行的所有字段都为 NULL 时,IS NULL将为真; 当行表达式本身不为 NULL 并且该行的所有字段都不为 NULL 时,IS NOT NULL 也将为真。因为这个行为,IS NULL和IS NOT NULL 并不总是为行值表达式返回相反的值,也就是, 一个同时包含NULL和non-null值的行值表达式将在两种情况下都返回false。 这个规定符合 SQL 标准,但是与PostgreSQL之前的版本不兼容。
解读
就是说,对于rowType这种数据行类型,只有不存在记录或者记录的所有字段都是null时候 is null 才=true,
而is not null的判断是–存在记录且记录里面所有字段都不能是null…
所以上面的判断就让一些小老弟可以不停买票了…身为作者就当不知道算了,票也不要退…
解决方案
用 if [not] exists 来判断有没有记录会方便一点,或者说,不想再一次表的情况下,想要用rowType判断的,那么就直接用:
if rowType_order_signed_up."userId" is not null then
直接用rowType里面的某个肯定不是null的字段来判断