Me pregunto si hay una manera de insertar un registro en una tabla solo si la tabla no contiene ese registro?Insertar registro solo si el registro no existe ya en la tabla
¿Hay alguna consulta que haga esto o necesitaré un procedimiento almacenado?
Me pregunto si hay una manera de insertar un registro en una tabla solo si la tabla no contiene ese registro?Insertar registro solo si el registro no existe ya en la tabla
¿Hay alguna consulta que haga esto o necesitaré un procedimiento almacenado?
No dice qué versión de SQL Server. Si SQL Server 2008 se puede utilizar MERGE
NB: Es habitual utilizar la combinación de una Upsert que es lo que originalmente pensaba que la pregunta estaba pidiendo pero es válida sin la cláusula WHEN MATCHED
y acaba con una cláusula WHEN NOT MATCHED
lo mismo ocurre con el trabajo para este caso también Ejemplo de uso
CREATE TABLE #A(
[id] [int] NOT NULL PRIMARY KEY CLUSTERED,
[C] [varchar](200) NOT NULL)
MERGE #A AS target
USING (SELECT 3, 'C') AS source (id, C)
ON (target.id = source.id)
/*Uncomment for Upsert Semantics
WHEN MATCHED THEN
UPDATE SET C = source.C */
WHEN NOT MATCHED THEN
INSERT (id, C)
VALUES (source.id, source.C);
En términos de ejecución cuesta los dos parecen más o menos iguales cuando una inserción que hay que hacer ...
Link to plan images for first run
pero en la segunda pasada cuando no hay un inserto que ser hecho de Mateo la respuesta parece menor costo. No estoy seguro de si hay alguna manera de mejorar esto.
Link to plan images for second run
script de prueba
select *
into #testtable
from master.dbo.spt_values
CREATE UNIQUE CLUSTERED INDEX [ix] ON #testtable([type] ASC,[number] ASC,[name] ASC)
declare @name nvarchar(35)= 'zzz'
declare @number int = 50
declare @type nchar(3) = 'A'
declare @low int
declare @high int
declare @status int = 0;
MERGE #testtable AS target
USING (SELECT @name, @number, @type, @low, @high, @status) AS source (name, number, [type], low, high, [status])
ON (target.[type] = source.[type] AND target.[number] = source.[number] and target.[name] = source.[name])
WHEN NOT MATCHED THEN
INSERT (name, number, [type], low, high, [status])
VALUES (source.name, source.number, source.[type], source.low, source.high, source.[status]);
set @name = 'yyy'
IF NOT EXISTS
(SELECT *
FROM #testtable
WHERE [type] = @type AND [number] = @number and name = @name)
BEGIN
INSERT INTO #testtable
(name, number, [type], low, high, [status])
VALUES (@name, @number, @type, @low, @high, @status);
END
No estoy seguro de qué versión estoy usando actualmente. ¿Cómo funcionaría la fusión? –
@Mega - He actualizado mi respuesta con un ejemplo de cómo 'MERGE' podría usarse para este caso. Revisaré las estadísticas de ejecución para ver si hay alguna diferencia entre los 2 enfoques. –
El problema es la corrección, no el rendimiento. 'SI NO EXISTE (SELECCIONA ...) INSERT' causará errores duplicados bajo carga, garantizados. –
IF NOT EXISTS
(SELECT {Columns}
FROM {Table}
WHERE {Column1 = SomeValue AND Column2 = SomeOtherVale AND ...})
INSERT INTO {Table} {Values}
-1 ya que esta es ** la forma de sureshot ** de obtener errores duplicados bajo alta carga. SELECT e INSERT se ejecutan en momentos diferentes y no hay nada que evite que dos subprocesos concurrentes intenten insertar el mismo valor. MERGE, según lo publicado por Martin, es una solución adecuada –
En resumen, se necesita una mesa garantizada para ofrecerle la posibilidad de devolver una fila:
Insert dbo.Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3',....
From Information_Schema.Tables
Where Table_Schema = 'dbo'
And Table_Name = 'Table'
And Not Exists (
Select 1
From dbo.Table
Where Col1 = 'Foo'
And Col2 = 'Bar'
And ....
)
que he visto en esta variación el salvaje también:
Insert Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3'....
From (
Select 1 As Num
) As Z
Where Not Exists (
Select 1
From Table
Where Col1 = Foo
And Col2 = Bar
And ....
)
Tengo que votar para agregar un CONSTRAINT
. Es la respuesta más simple y más robusta. Quiero decir, mirando lo complicadas que son las otras respuestas, diría que es mucho más difícil hacerlo bien (y mantenerse en lo cierto).
Las desventajas: [1] al leer el código, no es obvio que se aplica la exclusividad en el DB [2] que el código del cliente debe conocer para detectar una excepción. En otras palabras, el tipo que viene después podría preguntarse "¿cómo funcionó esto alguna vez?"
Aparte de eso: solía preocuparme de que lanzar/atrapar la excepción fuera un golpe de rendimiento, pero hice algunas pruebas (en SQL Server 2005) y no fue significativo.
¿Ha considerado agregar una restricción de exclusividad? – bmm6o