¿Cómo insertar o actualizar usando una sola consulta?


26

Tengo una prueba de tabla con ID de columnas, qué clave principal y autoincrementado y nombre. Quiero insertar un nuevo registro si y solo si no hay registros. Por ejemplo

input es id = 30122 y name = john

si hay registros con la identificación 30122, entonces he actualizado la columna de nombre a John, si no hay registros, entonces inserto un nuevo registro.

Puedo hacerlo usando 2 consultas como

select * from test where id=30122

si tiene algunos registros, entonces puedo usar update test set name='john' where id=3012

o si no tiene registros, entonces puedo usar

insert into test(name) values('john')

¿Pero quería usar una sola consulta?

¿Alguien puede decir si es posible?


1
But I wanted to use single query?¿Por qué?
Aaron Bertrand

@AaronBertrand Mi back-end se desarrolla usando java. Entonces, si uso 2 quries, entonces tengo que presionar el DB 2 veces. Entonces, si se puede hacer usando una sola consulta, ¿por qué usar 2 consultas
SpringLearner

1
¿Java no admite un procedimiento almacenado o un solo lote con dos declaraciones que requieren solo un hit en la base de datos?
Aaron Bertrand

@ AaronBertrand, ¿podría dar un ejemplo de cómo manejaría esto con SQL Server 2008 o posterior?
eaglei22

1
@ eaglei22 Usaría el segundo ejemplo en la respuesta de vijayp a continuación. Todavía no elegiría MERGEen ninguna versión, incluso SQL Server 2019. Algunos antecedentes sobre eso aquí .
Aaron Bertrand

Respuestas:


41

Puedes probar esto

IF EXISTS(select * from test where id=30122)
   update test set name='john' where id=3012
ELSE
   insert into test(name) values('john');

Otro enfoque para un mejor rendimiento es

update test set name='john' where id=3012
IF @@ROWCOUNT=0
   insert into test(name) values('john');

y también lea estos malos hábitos para iniciar el prefijo de esquema


44
El primer ejemplo es derrochador y a menudo puede conducir a puntos muertos: no lo sugeriría en absoluto.
Aaron Bertrand

@AaronBertrand ¿quieres elaborar? Gracias
Hexo

55
@SlapY Claro, en el primer ejemplo, estás diciendo: "Hola, SQL Server, ¿hay una fila con esta ID?" SQL Server se apaga para encontrar la fila, tal vez usando un escaneo, y luego regresa con la respuesta. "¡Sí, usuario, tengo una fila con esa ID!" Luego dices: "Está bien, SQL Server, ve a buscar esa fila de nuevo , pero esta vez, ¡actualízalo!" ¿Ves cómo realizar la búsqueda o el escaneo dos veces es un desperdicio? ¿Te imaginas lo que sucede si otro usuario le hace a SQL Server la misma pregunta sobre la existencia de una fila, antes de que hagas algo al respecto?
Aaron Bertrand

Gracias, simplemente no veo por qué la primera amenaza con un punto muerto mientras que la segunda no. Ambos consisten en múltiples declaraciones que pueden ser interceptadas si no se ejecutan con bloqueo completo. ¿Me equivoco?
Hexo

2
@ 0x25b3 No es que uno esté amenazado por puntos muertos y el otro no, es que el primer ejemplo es mucho más propenso a ellos. Debería concluir en una transacción completa y adecuada en cualquier caso, pero la gente no, así que ...
Aaron Bertrand

17

Asumiendo SQL Server 2008 o posterior, puede usar MERGE:

Mesa

CREATE TABLE dbo.Test
(
    id integer NOT NULL,
    name varchar(30) NULL,

    CONSTRAINT PK_dbo_Test__id
        PRIMARY KEY CLUSTERED (id)
);

Consulta

MERGE dbo.Test WITH (SERIALIZABLE) AS T
USING (VALUES (3012, 'john')) AS U (id, name)
    ON U.id = T.id
WHEN MATCHED THEN 
    UPDATE SET T.name = U.name
WHEN NOT MATCHED THEN
    INSERT (id, name) 
    VALUES (U.id, U.name);

La SERIALIZABLEsugerencia es necesaria para un funcionamiento correcto con alta concurrencia .

Puede encontrar una comparación de los métodos comunes de Michael J. Swart aquí:

Mitos: soluciones simultáneas de actualización / inserción


8
La fusión tiene algunos problemas .
vonPryz

El enlace del mito allí es excelente. ¡Buena esa!
JonnyRaa
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.