Як вставити або оновити за допомогою одного запиту?


26

У мене є тестова таблиця з ідентифікаторами стовпців, який первинний ключ та автоматичне збільшення та ім'я. Я хочу вставити нову запис, якщо і не тільки, якщо немає записів. Наприклад

вхід - id = 30122, а ім'я = john

якщо є записи з id 30122, тоді я оновив стовпчик імен до john, якщо немає записів, то я вставив новий запис.

Я можу виконати 2 запити на кшталт

select * from test where id=30122

якщо він має деякі записи, то я можу використовувати update test set name='john' where id=3012

або якщо у нього немає записів, я можу використовувати

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

Але я хотів використовувати один запит?

Хтось може сказати, чи можливо це?


1
But I wanted to use single query?Чому?
Аарон Бертран

@AaronBertrand Мій задній кінець розроблений за допомогою Java.Так що, якщо я використовую 2 запити, мені доведеться натиснути БД у 2 рази. Отже, якщо це можна зробити за допомогою одного запиту, то навіщо використовувати 2 запити
SpringLearner

1
Java не підтримує збережену процедуру або одну партію з двома заявами, що вимагають лише одного звернення до бази даних?
Аарон Бертран

@AaronBertrand ви можете навести приклад того, як ви впораєтеся з цим на сервері sql 2008 або пізнішої версії?
eaglei22

1
@ eaglei22 Я б використав другий приклад у відповіді vijayp нижче. Я б все одно не вибирав MERGEжодної версії, навіть SQL Server 2019. Деякі передумови тут .
Аарон Бертран

Відповіді:


41

Ви можете спробувати це

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

Інший підхід для кращої роботи

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

а також прочитати цю шкідливу звичку натискати на префікс схеми


4
Перший приклад марнотратний і часто може призвести до тупиків - я б зовсім не пропонував це.
Аарон Бертран

@AaronBertrand прагнете розробити? Спасибі
Hexo

5
@SlapY Звичайно, у першому прикладі ви говорите: "Ей, SQL Server, чи є ряд з цим ідентифікатором?" SQL Server відходить на пошук рядка, можливо, використовуючи сканування, а потім повертається з відповіддю. "Чому так, користувачеві, я маю ряд з цим ідентифікатором!" Тоді ви скажете: "Гаразд, SQL Server, перейди знайди цей рядок ще раз , але цього разу онови його!" Чи бачите ви, як виконання пошуку або сканування двічі є марним? Ви можете собі уявити, що станеться, якщо інший користувач задасть SQL Server те саме запитання про існування рядка, перш ніж ви перейдете до того, щоб зробити щось з цього питання?
Аарон Бертран

Дякую, я просто не розумію, чому перший загрожує тупиком, а другий - це не так? Обидва складаються з декількох висловлювань, які можуть бути перехоплені, якщо не працювати з повним блокуванням. Я помиляюся?
Гексо

2
@ 0x25b3 Це не те, що одному загрожують тупики, а іншому - це не те, що перший приклад їм набагато більше схильний. У будь-якому випадку вам слід завершити повну та належну транзакцію, але люди так не роблять ...
Аарон Бертран

17

Припускаючи, що SQL Server 2008 або новішої версії, ви можете використовувати MERGE:

Таблиця

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

    CONSTRAINT PK_dbo_Test__id
        PRIMARY KEY CLUSTERED (id)
);

Запит

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

SERIALIZABLEПідказка необхідна для правильної роботи під високим паралелізмом .

Ви можете знайти порівняння поширених методів Майкла Дж. Суарта тут:

Міфування: одночасне оновлення / вставка рішень


8
Злиття має деякі проблеми .
vonPryz

посилання на міф, що перебуває там, є чудовою. Хороший!
JonnyRaa
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.