Sqlite вставить в с уникальными именами, получить идентификатор - PullRequest
4 голосов
/ 10 мая 2009

У меня есть список строк для вставки в БД. Они ДОЛЖНЫ быть уникальными. Когда я вставляю, я хотел бы, чтобы их идентификатор (чтобы использовать в качестве внешнего ключа в другой таблице), поэтому я использую last_insert_rowid. У меня 2 проблемы.

  1. Если я использую замену, их идентификатор (INTEGER PRIMARY KEY) обновления, которые ломает мою БД (записи указывают на несуществующие идентификаторы)
  2. Если я использую игнорировать, rowid не обновляется, поэтому я не получаю правильный идентификатор

Как мне получить их идентификаторы? если мне не нужно, я бы не хотел использовать оператор select для проверки и вставки строки, если она не существует. Как мне это сделать?

Ответы [ 3 ]

8 голосов
/ 27 января 2011

Когда происходит нарушение ограничения UNIQUE, алгоритм REPLACE удаляет ранее существующие строки, которые вызывают нарушение ограничения, перед вставкой или обновлением текущей строки, и команда продолжает нормально выполняться. Это приводит к изменению rowid и создает следующую проблему

Y:> **sqlite3 test**  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> **create table b (c1 integer primary key, c2 text UNIQUE);**  
sqlite> **insert or replace into b values (null,'test-1');**  
sqlite> **select last_insert_rowid();**  
1  
sqlite> **insert or replace into b values (null,'test-2');**  
sqlite> **select last_insert_rowid();**  
2  
sqlite> **insert or replace into b values (null,'test-1');**  
sqlite> **select last_insert_rowid();**  
3  
sqlite> **select * from b;**  
2|test-2  
3|test-1  

Обходной путь - изменить определение столбца c2 следующим образом

create table b (c1 integer primary key, c2 text UNIQUE ON CONFLICT IGNORE);

и удалить из ваших вставок предложение «или заменить»;

тогда при тестировании после вставки вам нужно будет выполнить следующий sql: select last_insert_rowid(), changes();

sqlite> **create table b (c1 integer primary key, c2 text UNIQUE ON CONFLICT IGNORE);**  
sqlite> **insert into b values (null,'test-1');**  
sqlite> **select last_insert_rowid(), changes();**  
1|1  
sqlite> **insert into b values (null,'test-2');**  
sqlite> **select last_insert_rowid(), changes();**  
2|1  
sqlite> **insert into b values (null,'test-1');**  
sqlite> **select last_insert_rowid(), changes();**  
2|0  

Возвращаемым значением изменений после 3-й вставки будет уведомление вашего приложения о том, что вам нужно будет найти идентификатор строки «test-1», поскольку он уже был в файле. Конечно, если это многопользовательская система, вам нужно будет также обернуть все это в транзакцию.

3 голосов
/ 28 января 2011

Я использую ниже в настоящее время

insert into tbl(c_name) select 'val' where not exists(select id from tbl where c_name ='val');
select id from tbl where c_name ='val';
1 голос
/ 10 мая 2009

Под "они ДОЛЖНЫ быть уникальными", они означают, что вы уверены, что они есть, или что в результате вы хотите получить ошибку, если это не так? Если вы просто сделаете саму строку ключом в своей таблице, то я не понимаю, как 1 или 2 могут быть проблемой - вы получите нужную ошибку в случае нежелательного дублирования, в противном случае правильный ID. Возможно, вы сможете уточнить свой вопрос с помощью небольшого примера кода SQL, который вы используете, таблицы, о которой вы говорите, какое поведение вы наблюдаете и какое поведение вы хотите вместо этого ...?

Отредактировано: спасибо за редактирование, но мне все еще неясно, что SQL вызывает у вас какие проблемы! Если ваш стол пришел, например:

CREATE TABLE Foo(
  theid INTEGER PRIMARY KEY AUTOINCREMENT,
  aword TEXT UNIQUE ABORT
  )

тогда любая попытка ВСТАВИТЬ дублирующееся слово потерпит неудачу (ключевое слово ABORT является необязательным, так как это значение по умолчанию для UNIQUE) - это не то, что вы хотите , если вы говорите слова «ДОЛЖНЫ быть уникальными», то есть, если они не являются ошибкой?

...