Prz*_*mek 6 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;
Run Code Online (Sandbox Code Playgroud)
但是,我想使用val_2列的DEFAULT值而不是NULL- 如果NULL作为param_2值提供.
像这样的东西:
INSERT INTO my_table(val_1, val_2) VALUES (param_1, COALESCE(param_2, DEFAULT));
Run Code Online (Sandbox Code Playgroud)
显然是错误的,因为INSERT语句规范明确声明了一个表达式OR DEFAULT可以使用,DEFAULT它本身在表达式中不可用.
我自己找到了两种解决方案,但我对它们并不满意.
DEFAULT从信息模式中选择值并在COALESCE表达式中使用它.我不是专家,但似乎应该有一种更简单,更优雅的方式来做到这一点.
INSERT然后UPDATE像这样:
-- ...
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;
-- ...
Run Code Online (Sandbox Code Playgroud)
然而,这个解决方案有一个问题.生产系统的实际表有一些复杂的触发器,它们运行UPDATE在这个表上的语句中,所以我通常希望尽可能避免使用更新.
一般来说,我可能会坚持使用第二种解决方案,但这可能需要为上述触发器添加一些黑客攻击.但如果有办法避免这种情况 - 我将非常感激地指出它.
评论有点长。
一种方法是声明列NOT NULL。插入NULL值会产生约束违规,您可以在insertusing中捕获它on constraint。
这似乎是一个正确的方法。如果该列有默认值,那么您可能不希望它是NULL。
因为param_2只能是其中一个null或not 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
Run Code Online (Sandbox Code Playgroud)
如果需要返回插入的值:
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
Run Code Online (Sandbox Code Playgroud)