如何使用主键和 UNIQUE 列对 table 执行更新插入

How to perform an upsert on a table with both a primary key and UNIQUE column

SQLite 新手,正在尝试了解更新插入功能。

我有一个 table 具有以下 DDL:

CREATE TABLE contacts (
    contact_id INTEGER PRIMARY KEY,
    first_name TEXT NOT NULL,
    last_name TEXT NOT NULL,
    email TEXT NOT NULL UNIQUE,
    phone TEXT NOT NULL UNIQUE
);

假设我插入一条记录:

INSERT INTO contacts (contact_id, first_name, last_name, email, phone)
VALUES (1, 'John', 'Jones', 'jjones@gmail.com', '888-867-5309');

我如何做一个同时考虑 UNIQUE 约束 (email) 和 PK 约束 (contact_id) 的更新插入,以便它处理这两种情况,因为我不知道哪个约束将失败。

我试过这样做:

INSERT INTO contacts (contact_id, first_name, last_name, email, phone)
VALUES (1, 'John', 'Jones', 'john.jones@gmail.com', '888-867-5309')
ON CONFLICT (contact_id, email) DO UPDATE
SET first_name='John', last_name='Jones', email='john.jones@gmail.com', phone='888-867-5309'
WHERE contact_id=1;

但我收到错误:

sqlite3.OperationalError: ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint

单独执行它们就可以了。

INSERT INTO contacts (contact_id, first_name, last_name, email, phone)
VALUES (1, 'John', 'Jones', 'john.jones@gmail.com', '888-867-5309')
ON CONFLICT (contact_id) DO UPDATE
SET first_name='John', last_name='Jones', email='john.jones@gmail.com', phone='888-867-5309'
WHERE contact_id=1;
INSERT INTO contacts (contact_id, first_name, last_name, email, phone)
VALUES (1, 'John', 'Jones', 'john.jones@gmail.com', '888-867-5309')
ON CONFLICT (email) DO UPDATE
SET first_name='John', last_name='Jones', email='john.jones@gmail.com', phone='888-867-5309'
WHERE email='john.jones@gmail.com';

我知道我收到错误是因为列的组合不满足单个约束,它包含两个。但是我该如何兼顾两者呢?

因为你定义了:

contact_id INTEGER PRIMARY KEY

contact_idAUTOINCREMENT 并且您必须 而不是 在插入新行时明确为此列设置一个值(尽管 SQLite 不会抱怨如果如果没有冲突,你会这样做)。
所以你只需要:

INSERT INTO contacts (first_name, last_name, email, phone)
VALUES ('John', 'Jones', 'john.jones@gmail.com', '888-867-5309')
ON CONFLICT (email) DO UPDATE
SET first_name='John', last_name='Jones', email='john.jones@gmail.com', phone='888-867-5309'; 

但是,您还定义了:

phone TEXT NOT NULL UNIQUE

因此您的 table 中有 2 个 UNIQUE 约束。
对于这种情况,如果您希望 SQLite 处理来自两列的冲突,您可以使用 (INSERT OR) REPLACE:

REPLACE INTO contacts (first_name, last_name, email, phone)
VALUES('Johny', 'Jones', 'john.jones@gmail.com', '888-867-5309')

你必须知道如果没有冲突 REPLACE 插入新行(在你的情况下对于列 emailphone),但是如果有冲突那么删除一个或多个冲突行(因为会有 2 个冲突行,一个用于 email,另一个用于 phone)并插入新行。