Come inserire o aggiornare utilizzando una singola query?


26

Ho un test di tabella con ID colonne quale chiave primaria, auto incrementato e nome. Voglio inserire un nuovo record se annd solo se non ci sono record. Ad esempio

input è id = 30122 e nome = john

se ci sono record con ID 30122, allora ho aggiornato la colonna del nome a john, se non ci sono record, ho inserito un nuovo record.

Posso fare usando 2 query come

select * from test where id=30122

se ha alcuni record, allora posso usare update test set name='john' where id=3012

o se non ha record, allora posso usare

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

Ma volevo usare una singola query?

Qualcuno può dire se è possibile?


1
But I wanted to use single query?Perché?
Aaron Bertrand

@AaronBertrand Il mio back-end è stato sviluppato utilizzando java. Quindi, se uso 2 qury, allora devo colpire il DB 2 volte. Quindi, se è possibile farlo utilizzando una singola query, perché utilizzare 2 query
SpringLearner

1
Java non supporta una procedura memorizzata o un singolo batch con due istruzioni che richiedono un solo hit nel database?
Aaron Bertrand

@AaronBertrand potresti fare un esempio di come gestiresti questo con SQL Server 2008 o successivo?
eaglei22,

1
@ eaglei22 Vorrei usare il secondo esempio nella risposta di vijayp di seguito. Non sceglierei ancora MERGEin nessuna versione, nemmeno SQL Server 2019. Alcuni retroscena su questo qui .
Aaron Bertrand

Risposte:


41

Puoi provare questo

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

Altro approccio per prestazioni migliori è

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

e leggi anche queste cattive abitudini per dare il via al prefisso dello schema


4
Il primo esempio è dispendioso e spesso può portare a deadlock - non lo suggerirei affatto.
Aaron Bertrand

@AaronBertrand ti interessa elaborare? Grazie
Hexo,

5
@SlapY Certo, nel primo esempio, stai dicendo: "Ehi, SQL Server, c'è una riga con questo ID?" SQL Server si spegne per trovare la riga, magari utilizzando una scansione, quindi torna con la risposta. "Perché, sì, utente, ho una riga con quell'ID!" Quindi dici "Va bene, SQL Server, vai a trovare di nuovo quella riga , ma questa volta aggiornala!" Vedi quanto è dispendioso eseguire la ricerca o la scansione due volte? Riesci a immaginare cosa succede se un altro utente pone a SQL Server la stessa domanda sull'esistenza di una riga, prima di passare a fare qualcosa al riguardo?
Aaron Bertrand

Grazie, non vedo perché il primo è in pericolo di deadlock mentre il secondo no? Entrambi sono costituiti da più istruzioni che possono essere intercettate se non eseguite con il blocco completo. Ho sbagliato?
Hexo,

2
@ 0x25b3 Non è che uno sia minacciato da deadlock e l'altro no, è che il primo esempio è molto più incline a loro. Dovresti concludere una transazione completa e corretta in entrambi i casi, ma la gente no, quindi ...
Aaron Bertrand

17

Supponendo che SQL Server 2008 o successivo, è possibile utilizzare MERGE:

tavolo

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

    CONSTRAINT PK_dbo_Test__id
        PRIMARY KEY CLUSTERED (id)
);

domanda

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

Il SERIALIZABLEsuggerimento è necessario per il corretto funzionamento in condizioni di concorrenza elevata .

Puoi trovare un confronto dei metodi comuni di Michael J. Swart qui:

Mythbusting: soluzioni simultanee di aggiornamento / inserimento


8
L'unione ha alcuni problemi .
vonPryz,

il collegamento mitico lì è eccellente. Ben fatto!
JonnyRaa,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.