Patrick Skelton Ответов: 1

Как вставить запись в таблицу sqlite только в том случае, если она еще не существует?


Я приношу свои извинения, если этот вопрос не очень хорошо подходит для CodeProject, но я нашел вопросы SQLite здесь, так что здесь идет...

Я хочу создать "атомарный" SQL-скрипт, который вставит запись в таблицу только в том случае, если первичный ключ предоставленной записи еще не существует, таким образом избегая исключения ограничения, которое возникает, если вставка продолжается.

У меня есть следующий сценарий, который неверен. Я получаю ошибку, говоря, что синтаксис неправильный рядом с "где".

BEGIN EXCLUSIVE TRANSACTION;

INSERT INTO NetworkLocks
(
	PK_id,
	owner_username,
	unique_identifier,
	creation_time
)
VALUES
(
	@ID,
	@owner_username,
	@unique_identifier,
	@creation_time
)
WHERE NOT EXISTS
	( SELECT * FROM NetworkLocks nl WHERE nl.PK_id = @ID );

END TRANSACTION;



Любая помощь или совет будут очень признательны. Кроме того, как Новичок в SQLite, мне трудно разобраться в том, как составлять запросы. Любые указатели на хорошие источники обучения для этого были бы великолепны.

Что я уже пробовал:

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

1 Ответов

Рейтинг:
2

Jochen Arndt

Первичный ключ-это столбец или группа столбцов, используемых для определения уникальности строк в таблице. Каждая таблица имеет один и только один первичный ключ.
Из-за уникальности попытка вставить строку (запись) с уже существующим первичным ключом завершится неудачей. Таким образом, вы можете просто попробовать вставить и сообщить об ошибках, если это необходимо.

В соответствии с вашим сценарием транзакции, PK_id является единственным столбцом для первичного ключа и поэтому должен быть уникальным. Какова цель этого проекта? unique_identifier значит, колонна?

[РЕДАКТИРОВАТЬ]
Чтобы устранить ошибку в SELECT использование оператора
( SELECT * FROM NetworkLocks WHERE PK_id = @ID );
Вы также можете указать столбцы с именем таблицы как NetworkLocks.PK_id.
[/РЕДАКТИРОВАТЬ]


Patrick Skelton

Спасибо за ответ.

В настоящее время мой код работает так, как вы описали. Я полагаюсь на уникальность первичного ключа (PK_id) и ловлю любое исключение. Однако это вполне предсказуемая ошибка. Это происходит при нормальной работе. Я не люблю исключений для этой ситуации. Я надеялся изменить SQL-скрипт так, чтобы он всегда выполнялся до завершения, но каким-то образом возвращал результат. Возможно, число затронутых строк может быть равно нулю вместо единицы?

Guid трудно объяснить. Возможно (хотя и маловероятно), что замки в этой таблице осиротеют, например, в результате отключения питания. Guid просто добавляет дополнительный уровень защиты, позволяя вызывающему потоку или экземпляру приложения без каких-либо сомнений знать, является ли он владельцем какой-либо данной записи блокировки.

Jochen Arndt

Вы не предоставили информацию о том, откуда вы это вызываете, но "поймать любое исключение" подразумевает какой-то язык программирования.

Обычным методом будет перехват исключений, потому что тогда вы можете положиться на потокобезопасность компонента database engine. Если вы сначала проверяете наличие записи, у вас могут быть условия гонки (которые не должны волновать, потому что вставка завершается неудачей, но снова вызывает исключение).

Я не уверен, что это может произойти и с такими сценариями транзакций. Но даже с помощью скрипта у вас есть дополнительный запрос, который все равно выполняется внутренне вставкой.

Patrick Skelton

Вы правы - это называется Через а C#.net .DLL API для SQLite.

Я думаю, что мне придется жить с подходом исключения. Я могу уменьшить вероятность возникновения исключения практически до нуля, выполнив быструю проверку кода C# перед попыткой вставки. Я понимаю, что это не потокобезопасно, но, как вы говорите, худшее, что может случиться,-это то, что последующая вставка вызывает исключение, которое мой код затем обрабатывает нормально.

Я удивлен, что мое, казалось бы, простое требование не легче реализовать.

Jochen Arndt

Вам все равно нужно ловить исключения, чтобы быть готовым и к другим ошибкам (особенно во время разработки, когда у вас могут быть синтаксические ошибки или опечатки в именах таблиц или столбцов).

Единственное решение, которое я могу придумать, - это проверить, предоставляет ли API также функции, которые не выбрасывают исключения, а вместо этого возвращают состояние.