鉴于此表:
create table test (
name text primary key
);
我需要编写一个plpgsql函数,其变量名与主键名冲突,我必须在on conflict
子句中使用它:
create or replace function func(
name text -- this variable name...
) returns void language plpgsql as
$$
begin
insert into test (name) values (name)
on conflict (name) do update -- ...conflicts with this line
set name = func.name;
end;
$$;
这会编译,但会抛出一个模糊的列引用:
select * from func('one');
ERROR: column reference "name" is ambiguous
LINE 2: on conflict (name) do update
^
DETAIL: It could refer to either a PL/pgSQL variable or a table column.
QUERY: insert into test (name) values (name)
on conflict (name) do update
set name = func.name
CONTEXT: PL/pgSQL function func(text) line 3 at SQL statement
我尝试将完整列名称指定为on conflict (test.name)
,但不编译,或((test.name))
编译:
create or replace function func(
name text
) returns void language plpgsql as
$$
begin
insert into test (name) values (name)
on conflict ((test.name)) do -- this fails too
update set name = func.name;
end;
$$;
但它也失败了:
select * from func('two');
ERROR: invalid reference to FROM-clause entry for table "test"
LINE 2: on conflict ((test.name)) do
^
HINT: There is an entry for table "test", but it cannot be referenced from this part of the query.
QUERY: insert into test (name) values (name)
on conflict ((test.name)) do
update set name = func.name
CONTEXT: PL/pgSQL function func(text) line 3 at SQL statement
有解决方案吗?
编辑:我找到了解决方法:
on conflict on constraint test_pkey do update
其中test_pkey
是表名加_pkey
。我不知道这有多可靠。我仍然想要指定列名。
答案 0 :(得分:3)
首先,name
是变量和属性的错误名称。当你有两者时,代码看起来不会很好。考虑到这一点,您可以使用带标记的块“加上”变量(在<<fn>>``), and set
variable_conflict`下面的示例中)以优先考虑列名,请参阅下面的代码:
t=# create or replace function func(
name text
) returns void language plpgsql as
$$
#variable_conflict use_column
<<fn>>
declare name text :='blah';
begin
insert into test (name) values (name)
on conflict (name) do -- this no longer fails
update set name = fn.name;
end;
$$;
t=# insert into test select 'b';
INSERT 0 1
Time: 8.076 ms
t=# select func('b');
func
------
(1 row)
Time: 6.117 ms
t=# select * from test;
name
------
b
blah
(2 rows)
https://www.postgresql.org/docs/current/static/plpgsql-implementation.html#PLPGSQL-VAR-SUBST
默认情况下,如果SQL语句中有名称,PL / pgSQL将报告错误 可以指变量或表列。你可以解决这个问题 通过重命名变量或列,或通过限定 模糊的引用,或通过告诉PL / pgSQL解释 偏爱。
进一步 - 基本上整个链接都是关于它的。
然而 - 在演示了如何使用plpgsql轻松完成特定任务之后,我仍然引用了namual:
最简单的解决方案是重命名变量或列。普通的 编码规则是为PL / pgSQL使用不同的命名约定 变量比用于列名称的变量。例如,如果你 一致地命名函数变量v_something而不是你的 列名以v_开头,不会发生冲突。
答案 1 :(得分:1)
ON CONFLICT...
语法(as documented here)使用唯一约束来确定行是否发生冲突。您可以通过列出它包含的列(此时Postgres&#34;推断&#34;要使用的正确索引)或直接命名约束来指定此唯一约束。
在您的情况下,使用的唯一约束是在CREATE TABLE
语句中隐式创建的主键约束。这将由DBMS给出一个名称,除非您直接指定一个;因此,您需要查找DBMS为其提供的名称(并且请注意,如果稍后重新创建模式,这可能会更改),或者在使用语法CONSTRAINT pk_some_name PRIMARY KEY
创建表时明确命名。 / p>
然后,您可以将该子句指定为ON CONFLICT ON CONSTRAINT pk_some_name DO ...
(注意约束名称周围没有括号)。
(或者,当然,您可以更改功能以使用明确的参数名称;就个人而言,我认为使用p_
或in_
这样的前缀而不是根据具体情况处理冲突。)