INSERT ... ON CONFLICT DO UPDATE 中的列引用不明确

zca*_*ate 1 sql postgresql upsert

给定一个表:

CREATE TABLE IF NOT EXISTS test."TestCounter" 
("id" TEXT PRIMARY KEY, 
 "count" INTEGER);
Run Code Online (Sandbox Code Playgroud)

我想插入一条记录并增加计数器(如果该记录已存在)

CREATE TABLE IF NOT EXISTS test."TestCounter" 
("id" TEXT PRIMARY KEY, 
 "count" INTEGER);
Run Code Online (Sandbox Code Playgroud)

目前我收到此错误:

ERROR:  column reference "count" is ambiguous
LINE 4:  SET "count" = "count" + 1
                       ^
SQL state: 42702
Character: 107
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 5

您需要对可能不明确的列进行表限定。
使用虚拟表名称excluded来引用输入行。但您可能想要引用目标列,因此请使用目标表的名称进行限定:

INSERT INTO test.test_counter (id)
VALUES ('id-0')
ON CONFLICT (id) DO UPDATE
SET count = test_counter.count + 1  -- here
RETURNING count;
Run Code Online (Sandbox Code Playgroud)

手册:

请注意,特殊excluded表用于引用最初建议插入的值。

虚拟输入表中的单行excluded包含目标表的所有INSERT列,即使未在或表达式的目标列列表中列出VALUEScount因此,无论是否明确针对目标,您遇到的歧义始终存在。

旁白:目标列列表中省略的列默认为其各自的列DEFAULT值,即NULL默认情况下(NULL即默认列DEFAULT)。即,它会默认NULL在您的设置和1下面我改进的设置中。BEFORE INSERT并应用行级触发器(如果有)。

但这都不适用于该示例,因为它毕竟引用了目标列。

值得注意的是,列名的其他两个实例count是明确的(因此不需要表限定),因为它们只能引用目标表。

当列count没有定义时,您的设置很容易被破坏NOT NULL,就像NULL + 1仍然一样NULL。这种设置会更有意义:

CREATE TABLE test.test_counter (
  id    text PRIMARY KEY
, count integer NOT NULL DEFAULT 1
);
Run Code Online (Sandbox Code Playgroud)

在我的示例中也没有使用带引号的 CaMeL 大小写名称。看: