[英]How to disambiguate a plpgsql variable name in a ON CONFLICT clause?
鑒於此表:
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))
:
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
。 我不知道這有多可靠。 我還是想指定列名。
首先, name
是變量和屬性的錯誤名稱。 當你有兩者時,代碼看起來不會很好。 考慮到這一點,您可以使用帶標記的塊“加”前綴變量(在<<fn>>``), and set
下面的示例中<<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_開頭,則不會發生沖突。
ON CONFLICT...
語法( 如此處所述 )使用唯一約束來確定行是否沖突。 您可以通過列出它包含的列(此時Postgres“推斷”要使用的正確索引)或直接命名約束來指定此唯一約束。
在您的情況下,使用的唯一約束是在CREATE TABLE
語句中隱式創建的主鍵約束。 這將由DBMS給出一個名稱,除非您直接指定一個; 因此,您需要查找DBMS提供的名稱(並注意稍后重新創建模式時可能會更改),或者在使用語法CONSTRAINT pk_some_name PRIMARY KEY
創建表時明確命名。
然后,您可以將該子句指定為ON CONFLICT ON CONSTRAINT pk_some_name DO ...
(注意約束名稱周圍沒有括號)。
(或者,當然,您可以更改函數以使用明確的參數名稱;就個人而言,我認為使用像p_
或in_
這樣的前綴而不是in_
處理沖突是一種好習慣。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.