当参数为 NULL 时将 DEFAULT 值插入列
Inserting DEFAULT value into a column when a parameter is NULL
我想写一个这样的存储过程:
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 DEFAULT
可以使用,DEFAULT
本身不是在表达式中可用。
我自己找到了两个解决方案,但我对它们都不满意。
- Select 来自信息模式的
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;
-- ...
但是这个解决方案有一个问题。生产系统的实际 table 有一些复杂的触发器 运行 on UPDATE
statements on this table 所以我通常希望尽可能避免使用更新。
一般来说,我可能会坚持使用第二种解决方案,但这可能需要对上述触发器添加一些技巧。但是如果有办法避免这种情况 - 我将非常感谢您指出它。
评论有点长
一种方法是声明列 NOT NULL
。插入 NULL
值会产生约束冲突,您可以使用 on constraint
.
在 insert
中捕捉到这种冲突
这似乎是一种正确的方法。如果列有默认值,那么您可能不希望它是 NULL
.
使用动态-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;
因为 param_2
只能是 null
或 not null
之一,只有一个选择将 return 插入一行:
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
如果需要return插入的值:
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
如果插入像问题中一样简单,我将使用两个不同的 INSERT
语句,因为生成的代码小且可读且速度快:
IF param_2 IS NULL THEN
INSERT INTO my_table(val_1) VALUES (param_1);
ELSE
INSERT INTO my_table(val_1, val_2) VALUES (param_1, param_2);
END IF;
对于更复杂的插入,例如使用多个可选参数,我可能会选择上面@lad2025 提供的 dynamic-SQL 解决方案。
我想写一个这样的存储过程:
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 DEFAULT
可以使用,DEFAULT
本身不是在表达式中可用。
我自己找到了两个解决方案,但我对它们都不满意。
- Select 来自信息模式的
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;
-- ...
但是这个解决方案有一个问题。生产系统的实际 table 有一些复杂的触发器 运行 on UPDATE
statements on this table 所以我通常希望尽可能避免使用更新。
一般来说,我可能会坚持使用第二种解决方案,但这可能需要对上述触发器添加一些技巧。但是如果有办法避免这种情况 - 我将非常感谢您指出它。
评论有点长
一种方法是声明列 NOT NULL
。插入 NULL
值会产生约束冲突,您可以使用 on constraint
.
insert
中捕捉到这种冲突
这似乎是一种正确的方法。如果列有默认值,那么您可能不希望它是 NULL
.
使用动态-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;
因为 param_2
只能是 null
或 not null
之一,只有一个选择将 return 插入一行:
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
如果需要return插入的值:
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
如果插入像问题中一样简单,我将使用两个不同的 INSERT
语句,因为生成的代码小且可读且速度快:
IF param_2 IS NULL THEN
INSERT INTO my_table(val_1) VALUES (param_1);
ELSE
INSERT INTO my_table(val_1, val_2) VALUES (param_1, param_2);
END IF;
对于更复杂的插入,例如使用多个可选参数,我可能会选择上面@lad2025 提供的 dynamic-SQL 解决方案。