Как выполнить upsert для таблицы как с первичным ключом, так и со столбцом UNIQUE - PullRequest
2 голосов
/ 16 октября 2019

Новичок в SQLite и пытается понять функциональность upsert.

У меня есть таблица со следующим 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');

Как я могу сделать upsert, который учитывает как ограничение 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 предложение не соответствует ни одному из ограничений PRIMARY KEY или UNIQUE

Выполнение их по отдельности работает просто отлично.

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';

Я понимаю, что получаю ошибку, потому что комбинация столбцов не соответствует одному ограничению, она охватывает два,Но как бы я принял это во внимание?

1 Ответ

3 голосов
/ 16 октября 2019

Поскольку вы определили:

contact_id INTEGER PRIMARY KEY

contact_id - это AUTOINCREMENT, и вы должны не явно установить значение для этого столбца при вставкеНовая строка (хотя 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

, поэтому в вашей таблице 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 вставляет новую строку, если естьнет конфликта (для столбцов email и phone в вашем случае), но если есть конфликт, то удаляет конфликтующую строку или строки (потому что будет 2 конфликтующих строки, одна для email, а другая для phone) и вставляет новый ряд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...