当参数为NULL

时间:2016-03-11 12:07:21

标签: postgresql stored-procedures plpgsql postgresql-9.4

我想写一个这样的存储过程:

CREATE OR REPLACE FUNCTION my_function(param_1 text, param_2 text DEFAULT NULL::text) RETURNS bigint AS
$$
DECLARE ret bigint;
BEGIN
    INSERT INTO my_table(val_1, val_2) VALUES (param_1, param_2);

    -- do some more stuff

    RETURN ret;
END;
$$
LANGUAGE plpgsql;

但是,我想使用val_2列的DEFAULT值代替NULL - 如果提供NULL作为param_2值。

这样的事情:

INSERT INTO my_table(val_1, val_2) VALUES (param_1, COALESCE(param_2, DEFAULT));

显然是错误的,因为INSERT语句规范明确指出可以使用表达式 OR DEFAULTDEFAULT本身在表达式中不可用。< / p>

我自己找到了两种解决方案,但我对它们并不满意。

  1. 从信息架构中选择DEFAULT值,并在COALESCE表达式中使用它。
  2. 我不是专家,但似乎应该有一种更简单,更优雅的方式。

    1. 使用INSERT然后UPDATE
    2. 像这样:

      -- ...
      INSERT INTO my_table(val_1) VALUES (param_1)
      RETURNING id INTO id_var;
      
      IF (param_2) IS NOT NULL THEN
          UPDATE my_table SET val_2 = param_2 WHERE id = id_var;
      END IF;
      -- ...
      

      然而,这个解决方案有一个问题。生产系统的实际表有一些错综复杂的触发器,它们在此表的UPDATE语句上运行,因此我通常希望尽可能避免使用更新。

      通常,我可能会坚持使用第二种解决方案,但这可能需要在上述触发器中添加一些黑客攻击。但如果有办法避免这种情况 - 我将非常感谢指出它。

3 个答案:

答案 0 :(得分:3)

评论时间有点长。

一种方法是声明列mysql -uroot -p --socket=/pathtoyour/new.sock 。插入NOT NULL值会产生约束违规,您可以使用NULLinsert中捕获。

这似乎是一种正确的方法。如果列具有默认值,那么您可能不希望它为on constraint

答案 1 :(得分:2)

使用dynamic-SQL:

CREATE OR REPLACE FUNCTION my_function(param_1 text, param_2 text DEFAULT NULL::text)
  RETURNS bigint AS
$$
DECLARE ret bigint;
BEGIN

 EXECUTE 'INSERT INTO my_table(val_1, val_2) VALUES (' ||
          quote_literal(param_1) || ',' ||
          CASE WHEN param_2 IS NULL THEN 'DEFAULT' ELSE quote_literal(param_2) END ||
          ')';

 RETURN ret;
END;
$$
LANGUAGE plpgsql;

SqlFiddleDemo

答案 2 :(得分:2)

由于param_2只能是nullnot null中的一个,所以只有一个选项会返回要插入的行:

with i as (
    insert into my_table (val_1)
    select param_1
    where param_2 is null
)
insert into my_table (val_1, val_2)
select param_1, param_2
where param_2 is not null

如果需要返回插入的值:

with i_null as (
    insert into my_table (val_1)
    select param_1
    where param_2 is null
    returning *
), i_notnull as (
    insert into my_table (val_1, val_2)
    select param_1, param_2
    where param_2 is not null
    returning *
)
select * from i_null
union all
select * from i_notnull