Pregunta

Tengo una lista de cadenas para insertar en una base de datos. DEBEN ser únicos. Cuando inserto me gustaría su ID (para usar como clave externa en otra tabla), así que uso last_insert_rowid. Tengo 2 problemas.

  1. Si uso reemplazar, su identificación (INTEGER PRIMARY KEY) actualiza qué rompe mi db (las entradas apuntan a ID inexistentes)
  2. Si uso ignore, rowid no se actualiza, por lo que no obtengo la ID correcta

¿Cómo obtengo sus ID? si no lo necesito, no quisiera usar una instrucción select para verificar e insertar la cadena si no existe. ¿Cómo debo hacer esto?

¿Fue útil?

Solución 2

Uso el siguiente actualmente

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

Otros consejos

Cuando se produce una violación de restricción ÚNICA, el algoritmo REPLACE elimina las filas preexistentes que causan la violación de restricción antes de insertar o actualizar la fila actual y el comando continúa ejecutándose normalmente. Esto hace que el rowid cambie y crea el siguiente 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 solución consiste en cambiar la definición de la columna c2 de la siguiente manera

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

y para eliminar " o reemplazar " cláusula de sus inserciones;

luego, cuando pruebe después de su inserción, deberá ejecutar el siguiente 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  

El valor de retorno de los cambios después de la tercera inserción será una notificación a su aplicación que necesitará buscar el rowid de " test-1 " ;, ya que ya estaba en el archivo. Por supuesto, si se trata de un sistema multiusuario, también deberá incluir todo esto en una transacción.

Por " DEBEN ser únicos " ;, ¿significan que está seguro de que lo son o que quiere un error como resultado si no lo son? Si solo hace que la cadena sea una clave en su tabla, entonces no entiendo cómo 1 o 2 podrían ser un problema: obtendrá un error como se desea en caso de duplicación no deseada, de lo contrario, la identificación correcta. Tal vez pueda aclarar su pregunta con un pequeño ejemplo de código SQL que está utilizando, la tabla en cuestión, qué comportamiento está observando y qué comportamiento desearía en su lugar ...

Editado: gracias por la edición, ¡pero aún no me queda claro qué SQL le está dando qué problemas! Si su tabla proviene, por ejemplo:

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

entonces cualquier intento de INSERTAR una palabra duplicada fallará (la palabra clave ABORT es opcional, ya que es la predeterminada para UNIQUE) - ¿no es eso lo que quiere dado que usted diga las palabras " DEBE ser único " ;, es decir, ¿es un error si no lo son?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top