variable_conflict use_variable不能与UPSERT的ON CONFLICT子句一起使用吗?

时间:2016-04-15 20:53:55

标签: postgresql postgresql-9.5

我经常使用variable_conflict use_variable,到目前为止我从来没有遇到任何问题。但是,它不适用于ON CONFLICT的{​​{1}}子句。这是我的复制品:

UPSERT

没有#variable_conflict use_variable一切正常:

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"

我错过了什么?

1 个答案:

答案 0 :(得分:1)

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

你可以在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允许在索引表达式中使用变量。

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