Sqlite insérer dans avec des noms uniques, obtenant id
-
20-08-2019 - |
Question
J'ai une liste de chaînes à insérer dans une base de données. Ils doivent être uniques. Lorsque j'insère, je souhaite que leur identifiant (à utiliser comme clé étrangère dans une autre table) afin que j'utilise last_insert_rowid. J'ai 2 problèmes.
- Si j'utilise replace, leur identifiant (INTEGER PRIMARY KEY) mises à jour qui casse ma db (les entrées pointent vers identifiants inexistants)
- Si j'utilise ignore, rowid n'est pas mis à jour, je ne reçois donc pas le bon identifiant
Comment puis-je obtenir leurs identifiants? si je n'en ai pas besoin, je ne voudrais pas utiliser une instruction select pour vérifier et insérer la chaîne si elle n'existe pas. Comment dois-je faire cela?
La solution 2
J'utilise actuellement le ci-dessous
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';
Autres conseils
Lorsqu'une violation de contrainte UNIQUE se produit, l'algorithme REPLACE supprime les lignes préexistantes à l'origine de la violation de contrainte avant l'insertion ou la mise à jour de la ligne actuelle et la commande continue de s'exécuter normalement. Cela provoque le rowid pour changer et crée le problème suivant
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
La solution consiste à modifier la définition de la colonne c2 comme suit
create table b (c1 integer primary key, c2 text UNIQUE ON CONFLICT IGNORE);
et supprimer le " ou remplacer " clause de vos insertions;
puis lorsque testez après votre insertion, vous devrez exécuter le code SQL suivant: 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
La valeur de retour des modifications après la 3ème insertion sera une notification à votre application que vous aurez besoin de rechercher le rowid de & "test-1 &"; étant donné qu'il figurait déjà dans le fichier. Bien sûr, s’il s’agit d’un système multi-utilisateurs, vous devrez également envelopper tout cela dans une transaction.
Par & "ils DOIVENT être uniques &", signifient-ils que vous êtes sûr qu'ils le sont ou que vous voulez une erreur s'ils ne le sont pas? Si vous ne faites que la chaîne elle-même une clé dans sa table, alors je ne comprends pas pourquoi 1 ou 2 pourraient être un problème - vous obtiendrez une erreur si vous le souhaitez en cas de duplication non souhaitée, sinon l'identifiant correct. Peut-être pouvez-vous clarifier votre question avec un petit exemple du code SQL que vous utilisez, la table en question, quel comportement observez-vous et quel comportement souhaitez-vous plutôt ...?
Modifié: merci pour la modification, mais je ne vois toujours pas ce que SQL vous pose quels problèmes! Si votre table provient de, par exemple:
CREATE TABLE Foo(
theid INTEGER PRIMARY KEY AUTOINCREMENT,
aword TEXT UNIQUE ABORT
)
toute tentative d'insérer un mot dupliqué échouera (le mot clé ABORT
est facultatif, car il s'agit du paramètre par défaut pour UNIQUE
). N'est-ce pas ce que vous voulez étant donné que vous prononcez les mots & "DOIT être unique &", c’est-à-dire qu’il s’agit d’une erreur s’ils ne le sont pas?