案例再现

某日,写一份关于判断是不是已经报名过的存储过程, 代码如下:

--变量定义区,定义一个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,在数据表一看,

pgmysql CriteriaBuilder in语句_SQL

这个小老弟都已经没了十张票了,真有趣.

然后一查文档…
坑爹啊

官方说明

提示: 有些应用可能要求表达式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之前的版本不兼容。

is null 与is not null

解读

就是说,对于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的字段来判断