variable_conflict use_variable 不使用 UPSERT 的 ON CONFLICT 子句吗?

Is variable_conflict use_variable not working with ON CONFLICT clause of UPSERT?

我经常使用 variable_conflict use_variable,到目前为止我从未遇到过任何问题。但是,它不适用于 UPSERTON CONFLICT 子句。这是我的复制品:

CREATE TABLE test(id serial not null,
  CONSTRAINT test_pk PRIMARY KEY(id),
  category_id INT NOT NULL,
  tname TEXT NOT NULL,
  CONSTRAINT test_unq UNIQUE(category_id, tname),
  some_info TEXT NOT NULL);
CREATE OR REPLACE FUNCTION insert_test(category_id INT, tname TEXT, some_info TEXT)
  RETURNS void AS
$BODY$
#variable_conflict use_variable
DECLARE
  resultId INTEGER;
BEGIN
  INSERT INTO test(category_id, tname, some_info)
      SELECT category_id, tname, some_info
      ON CONFLICT(category_id, tname) DO NOTHING;
END
$BODY$
  LANGUAGE plpgsql VOLATILE 
  COST 100;

SELECT insert_test(1, 'Colors', 'Blue');

ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
CONTEXT:  SQL statement "INSERT INTO test(category_id, tname, some_info)
      SELECT category_id, tname, some_info
      ON CONFLICT(category_id, tname) DO NOTHING"

没有#variable_conflict use_variable一切正常:

CREATE OR REPLACE FUNCTION insert_test2(p_category_id INT, p_tname TEXT, p_some_info TEXT)
  RETURNS void AS
$BODY$
DECLARE
  resultId INTEGER;
BEGIN
  INSERT INTO test(category_id, tname, some_info)
      SELECT p_category_id, p_tname, p_some_info
      ON CONFLICT(category_id, tname) DO NOTHING;
END
$BODY$
  LANGUAGE plpgsql VOLATILE 
  COST 100; 

SELECT insert_test2(1, 'Colors', 'Blue');
SELECT insert_test2(2, 'Colors', 'Red');

我错过了什么?

ON CONFLICT 子句依赖于索引定义,索引可以在其定义中使用任意表达式(不一定指的是 table 列)。

您可以在 PostgreSQL 9.5.2 中执行此操作:

test=# CREATE TABLE test (id BIGSERIAL NOT NULL PRIMARY KEY, value INT);
CREATE TABLE

test=# CREATE UNIQUE INDEX ix_test ON test (value, (1));
CREATE INDEX

test=# INSERT INTO test (value) VALUES (1);
INSERT 0 1

test=# INSERT INTO test (value) VALUES (1);
ERROR:  duplicate key value violates unique constraint "ix_test"
ПОДРОБНОСТИ:  Key (value, (1))=(1, 1) already exists.

test=# INSERT INTO test (value) VALUES (1) ON CONFLICT (value, (1)) DO NOTHING;
INSERT 0 0

test=# INSERT INTO test (value) VALUES (1) ON CONFLICT (value, (2)) DO NOTHING;
ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification

test=# INSERT INTO test (value) VALUES (1) ON CONFLICT (value, (id)) DO NOTHING;
ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification

test=# INSERT INTO test (value) VALUES (1) ON CONFLICT (value, (no_such_column)) DO NOTHING;
ERROR:  column "no_such_column" does not exist
СТРОКА 1: ...INTO test (value) VALUES (1) ON CONFLICT (value, (no_such_co...

test=# INSERT INTO test (value) SELECT * FROM (VALUES (1)) q (n) ON CONFLICT (value, (n)) DO NOTHING;
ERROR:  column "n" does not exist
СТРОКА 1: ...CT * FROM (VALUES (1)) q (n) ON CONFLICT (value, (n)) DO NOT...
ПОДСКАЗКА:  There is a column named "n" in table "*SELECT*", but it cannot be referenced from this part of the query.

test=# DROP FUNCTION IF EXISTS fn_test(INT); CREATE FUNCTION fn_test(n INT) RETURNS VOID AS $$ INSERT INTO test (value) VALUES (1) ON CONFLICT (value, (n)) DO NOTHING; $$ LANGUAGE 'sql';
DROP FUNCTION
CREATE FUNCTION

test=# SELECT * FROM fn_test(1);
ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
КОНТЕКСТ:  SQL function "fn_test" during startup

出于某种原因,在进行唯一索引推断时,PostgreSQL 允许在索引表达式中使用变量。

这可能是一个错误,因为我想不出任何合理的理由。