Postgresql 当涉及“唯一索引”时,为什么更新查询结果会有差异?

Postgresql 当涉及“唯一索引”时,为什么更新查询结果会有差异?,postgresql,Postgresql,我偶然遇到了一个问题,所以我试了一些东西 给定以下模式: create table scientist (id integer PRIMARY KEY, firstname varchar(100), lastname varchar(100)); insert into scientist (id, firstname, lastname) values (1, 'albert', 'einstein'); insert into scientist (id,

我偶然遇到了一个问题,所以我试了一些东西

给定以下模式:

create table scientist (id integer PRIMARY KEY, firstname varchar(100), lastname varchar(100));
        insert into scientist (id, firstname, lastname) values (1, 'albert', 'einstein');
        insert into scientist (id, firstname, lastname) values (2, 'isaac', 'newton');
        insert into scientist (id, firstname, lastname) values (3, 'marie', 'curie');
        select * from scientist;

CREATE UNIQUE INDEX fl_idx ON scientist(firstname, lastname);

运行此查询时:

UPDATE scientist AS c SET
    firstname = new_values.F,
    lastname = new_values.L
FROM (
    SELECT * FROM
        UNNEST(
            ARRAY[1, 1]::numeric[],
            ARRAY['one', 'v']::text[],
            ARRAY['three', 'f']::text[]
        ) AS T(
            I,
            F,
            L
        )
    ) AS new_values
WHERE c.id = new_values.I
RETURNING c.id, c.firstname, c.lastname;
我回来了:

id  firstname   lastname
1   one          three
然而,如果我不创建索引(
create UNIQUE index fl_idx ON scientist(firstname,lastname);
),我会得到:

因此,我不确定为什么
唯一索引
会影响结果,为什么当我将
UNNEST
更改为(类似于我上面提到的So问题)时,
id
主键时,
重复键值不会违反唯一约束
异常:

UNNEST(
    ARRAY[1, 1]::numeric[],
    ARRAY['one', 'one']::text[],
    ARRAY['three', 'three']::text[]
)
我运行上述查询的postgres版本是: x86_64-pc-linux-gnu上的PostgreSQL 11.11(Debian 11.11-0+deb10u1),由gcc(Debian 8.3.0-6)8.3.0编译,64位,来自:

使用FROM时,应确保联接为要修改的每一行最多生成一个输出行。换句话说,目标行不应连接到其他表中的多个行如果是,则只有一个联接行将用于更新目标行,但使用哪一个并不容易预测。

在本例中,1有两个匹配项,因此选择完全取决于读取的顺序行

以下是运行和结果都有索引的示例:



您知道为什么我没有得到“重复键值违反唯一约束”错误吗

执行更新后,列id上和对first\u name/last\u name上都没有重复的键

情景1:

+-----+------------+----------+
| id  | firstname  | lastname |
+-----+------------+----------+
|  2  | isaac      | newton   |
|  3  | marie      | curie    |
|  1  | v          | f        |
+-----+------------+----------+
情景2:

+-----+------------+----------+
| id  | firstname  | lastname |
+-----+------------+----------+
|  2  | isaac      | newton   |
|  3  | marie      | curie    |
|  1  | one        | three    |
+-----+------------+----------+
编辑:

使用“UPSERT”并尝试插入/更新行两次:

INSERT INTO scientist (id,firstname, lastname)
VALUES (1, 'one', 'three'), (1, 'v', 'f')
ON CONFLICT (id) 
DO UPDATE SET firstname = excluded.firstname;

-- ERROR:  ON CONFLICT DO UPDATE command cannot affect row a second time
发件人:

使用FROM时,应确保联接为要修改的每一行最多生成一个输出行。换句话说,目标行不应连接到其他表中的多个行如果是,则只有一个联接行将用于更新目标行,但使用哪一个并不容易预测。

在本例中,1有两个匹配项,因此选择完全取决于读取的顺序行

以下是运行和结果都有索引的示例:



您知道为什么我没有得到“重复键值违反唯一约束”错误吗

执行更新后,列id上和对first\u name/last\u name上都没有重复的键

情景1:

+-----+------------+----------+
| id  | firstname  | lastname |
+-----+------------+----------+
|  2  | isaac      | newton   |
|  3  | marie      | curie    |
|  1  | v          | f        |
+-----+------------+----------+
情景2:

+-----+------------+----------+
| id  | firstname  | lastname |
+-----+------------+----------+
|  2  | isaac      | newton   |
|  3  | marie      | curie    |
|  1  | one        | three    |
+-----+------------+----------+
编辑:

使用“UPSERT”并尝试插入/更新行两次:

INSERT INTO scientist (id,firstname, lastname)
VALUES (1, 'one', 'three'), (1, 'v', 'f')
ON CONFLICT (id) 
DO UPDATE SET firstname = excluded.firstname;

-- ERROR:  ON CONFLICT DO UPDATE command cannot affect row a second time

那很有趣,谢谢!你知道为什么我没有得到“重复键值违反唯一约束”错误吗?@Orestis没有重复项。相关:-这里不是PostgreSQL,但想法是一样的。当查询的unnest是:unnest(数组[1,1]::numeric[],数组['one','one']::text[],数组['three','three']::text[])时,我希望抛出因为我们尝试更新相同的id。我是否遗漏了什么?@Orestis仍然错误消息应该不同,因为没有重复。问题是您正在使用“波动”表作为源进行更新(可能有多个匹配)。这很有趣,谢谢!你知道为什么我没有得到“重复键值违反唯一约束”错误吗?@Orestis没有重复项。相关:-这里不是PostgreSQL,但想法是一样的。当查询的unnest是:unnest(数组[1,1]::numeric[],数组['one','one']::text[],数组['three','three']::text[])时,我希望抛出因为我们尝试更新相同的id。我是否遗漏了什么?@Orestis仍然错误消息应该不同,因为没有重复。问题是您正在使用“波动”表作为源进行更新(可能有多个匹配)。