给定此表:
create table test ( name text primary key );
我需要编写一个plpgsql函数,其变量名与主键名冲突,必须在on conflict子句中使用该主键名:
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))不编译:
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。我不知道这有多可靠。我仍然想改为指定列名。
test_pkey
_pkey
首先,name对于变量和属性都是一个不好的名字。两者兼而有之时,代码将看起来不那么好。考虑到这一点,您可以在变量前加上标签块(例如在<<fn>>``), and setvariable_conflict`下面的示例中,以优先选择列名,请参见下面的代码:
name
<<fn>>``), and set
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_开头,则不会发生冲突。