varios values tabla registros off into insertar identity_insert datos crear cambiar sql-server insert unique

sql-server - values - insertar varios registros en sql



SQL Server: cómo insertar un registro y asegurarse de que sea único (7)

declare @Error int begin transaction INSERT INTO Words (Word) values(@word) set @Error = @@ERROR if @Error <> 0 --if error is raised begin goto LogError end commit transaction goto ProcEnd LogError: rollback transaction

Estoy tratando de encontrar la mejor manera de insertar un registro en una sola tabla, pero solo si el elemento aún no existe. La LLAVE en este caso es un campo NVARCHAR (400). Para este ejemplo, imaginemos que es el nombre de una palabra en el Oxford English Dictionary / inserte su diccionario de favoritos aquí. Además, supongo que tendré que convertir el campo Word en una clave principal. (la tabla también tendrá un identificador único PK también).

Entonces ... podría obtener estas palabras que necesito agregar a la mesa ...

p.ej.

  • Gato
  • Perro
  • Foo
  • Bar
  • PewPew
  • etc ...

Tradicionalmente, probaría lo siguiente (pseudo código)

SELECT WordID FROM Words WHERE Word = @Word IF WordID IS NULL OR WordID <= 0 INSERT INTO Words VALUES (@Word)

es decir. Si la palabra no existe, insértela.

Ahora ... el problema que me preocupa es que estamos recibiendo MUCHOS éxitos ... así que es posible que la palabra se pueda insertar desde otro proceso entre el SELECTO y el INSERTO ... lo que arrojaría un error de restricción ? (es decir, una condición de carrera ).

Entonces pensé que podría hacer lo siguiente ...

INSERT INTO Words (Word) SELECT @Word WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

básicamente, inserte una palabra cuando no exista.

Aparte de la mala sintaxis, no estoy seguro de si esto es malo o bueno debido a la forma en que bloquea la tabla (si es así) y no es tan eficiente en una tabla que obtiene lecturas masivas y muchas escrituras.

Entonces, ¿qué piensan o hacen los gurús Sql?

Esperaba tener un simple inserto y ''atrapar'' eso para cualquier error lanzado.


No puedo hablar sobre los detalles de MS SQL, pero un punto de una clave principal en SQL es garantizar la exclusividad. Por definición, en términos genéricos de SQL, una clave principal es uno o más campos que son exclusivos de una tabla. Si bien existen diferentes formas de aplicar este comportamiento (reemplazar la entrada anterior por la nueva y rechazar la nueva) me sorprendería que MS SQL no tuviera un mecanismo para aplicar este comportamiento y que no fuera así. rechazar la nueva entrada. Solo asegúrese de configurar la clave principal en el campo Word y debería funcionar.

Sin embargo, una vez más, rechazo que todo esto proviene de mi conocimiento de la programación de MySQL y de mi clase de bases de datos, así que me disculpo si no estoy interesado en las complejidades de MS SQL.


Si está utilizando MS SQL Server, puede crear un índice único en las columnas de su tabla que debe ser único (documentado aquí ):

CREATE UNIQUE [ CLUSTERED | NONCLUSTERED ] INDEX <index_name> ON Words ( word [ ASC | DESC ])

Especifique NonClustered o No NonClustered , según su caso. Además, si lo desea ordenado (para permitir una búsqueda más rápida), especifique ASC o DESC para el orden de clasificación.

Consulte aquí si desea obtener más información sobre la arquitectura de índices.

De lo contrario, podría usar UNIQUE CONSTRAINTS como se documenta aquí :

ALTER TABLE Words ADD CONSTRAINT UniqueWord UNIQUE (Word);


mientras que la restricción única es ciertamente una forma de hacerlo, también puede usar esto para su lógica de inserción: http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

Básicamente, no coloca ningún candado en la tabla a continuación, así no se preocupa por las lecturas mientras sus comprobaciones de presencia se realizarán bien.

es un mutex en código sql.


Tuve un problema similar y así es como lo resolví

insert into Words ( selectWord , Fixword) SELECT word,''theFixword'' FROM OldWordsTable WHERE ( (word LIKE ''junk%'') OR (word LIKE ''orSomthing'') ) and word not in ( SELECT selectWord FROM words WHERE selectWord = word )


Creo que he encontrado una mejor (o al menos más rápida) respuesta para esto. Crea un índice como:

CREATE UNIQUE NONCLUSTERED INDEX [IndexTableUniqueRows] ON [dbo].[table] ( [Col1] ASC, [Col2] ASC, )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = ON, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

Incluya todas las columnas que definen la singularidad. La parte importante es IGNORE_DUP_KEY = ON. Eso convierte inserciones no únicas en advertencias. SSIS ignora estas advertencias y también puede usar la carga rápida.


Tu solución:

INSERT INTO Words (Word) SELECT @Word WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

... es casi tan bueno como se pone. Usted podría simplificarlo a esto:

INSERT INTO Words (Word) SELECT @Word WHERE NOT EXISTS (SELECT * FROM Words WHERE Word = @Word)

... porque EXISTS en realidad no necesita devolver ningún registro, por lo que el optimizador de consultas no se molestará en buscar los campos que solicitó.

Como mencionas, sin embargo, esto no es particularmente efectivo, porque bloqueará toda la tabla durante el INSERTAR. Excepto que, si agrega un índice único (no necesita ser la clave principal) a Word, entonces solo necesitará bloquear las páginas relevantes.

Su mejor opción es simular la carga esperada y observar el rendimiento con SQL Server Profiler. Como con cualquier otro campo, la optimización prematura es algo malo. Defina las métricas de rendimiento aceptables y luego mida antes de hacer cualquier otra cosa.

Si eso todavía no le da un rendimiento adecuado, entonces hay una serie de técnicas del campo de almacenamiento de datos que podrían ayudar.