Domanda

Ho un elenco di stringhe da inserire in un db. DEVONO essere unici. Quando inserisco vorrei il loro ID (da utilizzare come chiave esterna in un'altra tabella), quindi utilizzo last_insert_rowid. Ottengo 2 problemi.

  1. Se uso sostituire, il loro ID (INTEGER PRIMARY KEY) aggiorna quale rompe il mio db (le voci indicano ID inesistenti)
  2. Se uso ignore, rowid non viene aggiornato, quindi non ottengo l'ID corretto

Come ottengo i loro ID? se non ho bisogno non vorrei usare un'istruzione select per controllare e inserire la stringa se non esiste. Come dovrei farlo?

È stato utile?

Soluzione 2

Attualmente uso quanto segue

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

Altri suggerimenti

Quando si verifica una violazione UNIQUE del vincolo, l'algoritmo REPLACE elimina le righe preesistenti che causano la violazione del vincolo prima di inserire o aggiornare la riga corrente e il comando continua l'esecuzione normalmente. Ciò causa la modifica del rowid e crea il seguente problema

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 soluzione è di modificare la definizione della colonna c2 come segue

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

e per rimuovere il " o sostituire " clausola dai tuoi inserti;

quindi quando si esegue il test dopo l'inserimento, sarà necessario eseguire il seguente 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  

Il valore restituito delle modifiche dopo il 3o inserimento sarà una notifica alla tua applicazione che dovrai cercare il rowid di " test-1 " poiché era già in archivio. Ovviamente se si tratta di un sistema multiutente, dovrai anche includere tutto questo in una transazione.

Per " DEVONO essere univoci " ;, significano che sei sicuro che lo sono o che vuoi un errore come risultato se non lo sono? Se rendi la stringa stessa una chiave nella sua tabella, allora non capisco come sia 1 o 2 potrebbero essere un problema: otterrai un errore come desiderato in caso di duplicazione indesiderata, altrimenti l'ID corretto. Forse puoi chiarire la tua domanda con un piccolo esempio di codice SQL che stai utilizzando, la tabella in questione, quale comportamento stai osservando e quale comportamento vorresti invece ...?

Modificato: grazie per la modifica, ma non mi è ancora chiaro quale SQL ti dia quali problemi! Se il tuo tavolo proviene, ad esempio:

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

quindi qualsiasi tentativo di INSERIRE una parola duplicata fallirà (la ABORT parola chiave è facoltativa, poiché è l'impostazione predefinita per UNIQUE) - non è quello che vuoi dato che dì le parole " DEVE essere univoco " ovvero, è un errore se non lo sono?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top