Запит на оновлення за допомогою підзапиту в Sql Server


83

У мене є така проста структура таблиці:

Таблиця tempData

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║    80 ║
║ Ravi     ║    85 ║
║ Sanjay   ║    90 ║
╚══════════╩═══════╝

І у мене також є інші назви таблиць як tempDataView, як це

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Ravi     ║       ║
║ Ravi     ║       ║
║ Sanjay   ║       ║
╚══════════╩═══════╝

Я хочу оновити таблицю tempDataView , встановивши Позначки відповідно до tempDataView - Name порівняно з tempData - Name

Так, дозвольте мені показати вам, що я пробував, я намагався вирішити це за допомогою курсору і його вирішено ідеально, але я знаходжу спосіб вирішити це за допомогою підзапиту

Ось:

Declare @name varchar(50),@marks varchar(50)
Declare @cursorInsert CURSOR
set @cursorInsert = CURSOR FOR
Select name,marks from tempData
OPEN @cursorInsert
FETCH NEXT FROM @cursorInsert
into @name,@marks
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE tempDataView set marks = @marks where name = @name
FETCH NEXT FROM @cursorInsert
INTO @name,@marks
END
CLOSE @cursorInsert
DEALLOCATE @cursorInsert

Насправді для мене це як домашнє завдання, щоб вирішити його за допомогою підзапиту.

Відповіді:


180

ви можете приєднати обидві таблиці навіть до UPDATEоператорів,

UPDATE  a
SET     a.marks = b.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

для швидшої роботи визначте INDEXстовпець markson в обох таблицях.

використання SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )

1
це правильно. але, будь ласка, запропонуйте мені будь-який спосіб зробити це за допомогою підзапиту.
Narendra Pal

1
оновив відповідь за допомогою subquery, але я скоріше використовую JOINніж SUBQUERY.
John Woo

1
Чому слід визначати INDEXна marksстовпцях знак ? Це не повинно бути на Nameколонах?
lindelof

1
Виникла помилка: підзапит повернув більше 1 значення. Це заборонено, коли підзапит слідує =,! =, <, <=,>,> = Або коли підзапит використовується як вираз.
Прадіп

1
Спробуйте підзапит самостійно та коригуйте його, поки не отримаєте лише 1 результат. Можливо, змініть SELECTнаSELECT TOP 1
vahanpwns

33

оскільки ви тільки навчаєтесь, я пропоную вам потренуватися в перетворенні об’єднань SELECT на UPDATE або DELETE. Спочатку я пропоную вам створити оператор SELECT, що об’єднує ці дві таблиці:

SELECT *
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Тоді зверніть увагу, що у нас є два псевдоніми таблиці aта b. Використовуючи ці псевдоніми, ви можете легко генерувати оператор UPDATE для оновлення таблиці a або b. Для таблиці а ви отримали відповідь від JW. Якщо ви хочете оновити b, виписка буде такою:

UPDATE  b
SET     b.marks = a.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Тепер, щоб перетворити оператор у оператор DELETE, використовуйте той самий підхід. Викладене нижче вилучення буде видалено aлише з (залишити b недоторканим) для тих записів, які відповідають іменам:

DELETE a
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Ви можете використовувати скрипт SQL, створений JW, як ігровий майданчик


5
правильний спосіб навчання. +1 за вказівку шляху до навчання. Дякую
Нарендра Пал

3

Тут у своєму зразку я знаходжу рішення цього, оскільки у мене була та ж проблема з оновленнями та підзапросами:

UPDATE
    A
SET
    A.ValueToChange = B.NewValue
FROM
    (
        Select * From C
    ) B
Where 
    A.Id = B.Id

1
Дякую за цю відповідь! Щоб допомогти іншим читати це, чи можете ви швидко додати пояснення, чому цей код вирішує проблему?
RedBassett

0

Заголовок цього потоку запитує, як підзапит можна використовувати в оновленні. Ось приклад цього:

update [dbName].[dbo].[MyTable] 
set MyColumn = 1 
where 
    (
        select count(*) 
        from [dbName].[dbo].[MyTable] mt2 
        where
            mt2.ID > [dbName].[dbo].[MyTable].ID
            and mt2.Category = [dbName].[dbo].[MyTable].Category
    ) > 0

Я не впевнений, як би це навіть скомпілювалося, немає жодної групи, щоб граф (*) знав, що рахувати.
crthompson

@paqogomez просто спробуйте - на будь-якій таблиці, в якій є записи. е, г. виберіть кількість (*) з EventLog, де рік = 2018
Грем Лайт

Отже, ви просто підраховуєте всю таблицю. Я підтримую свій голос проти, це не має нічого спільного з запитанням (незалежно від назви)
crthompson,

Це ваша прерогатива, але заголовок цього потоку - "запит на оновлення з використанням підзапиту", і мій приклад самоочевидно робить саме це. fyi Я не рахую "всю таблицю" - за count (*) йде речення "where" - отже, це підрахунок рядків, які відповідають умові "where".
Graham Laight

0

Ось гарне пояснення операції оновлення з кількома прикладами. Хоча це сайт Postgres, але запити SQL є дійсними і для інших БД. Наступні приклади зрозумілі для інтуїції.

-- Update contact names in an accounts table to match the currently assigned salesmen:

UPDATE accounts SET (contact_first_name, contact_last_name) =
    (SELECT first_name, last_name FROM salesmen
     WHERE salesmen.id = accounts.sales_id);

-- A similar result could be accomplished with a join:

UPDATE accounts SET contact_first_name = first_name,
                    contact_last_name = last_name
  FROM salesmen WHERE salesmen.id = accounts.sales_id;

Однак другий запит може дати несподівані результати, якщо salesmen.id не є унікальним ключем, тоді як перший запит гарантовано спричинить помилку, якщо є кілька збігів ідентифікаторів. Крім того, якщо для певного запису accounts.sales_id немає відповідності, перший запит встановить для відповідних полів імен значення NULL, тоді як другий запит взагалі не оновить цей рядок.

Отже, для наведеного прикладу найнадійніший запит такий, як наведений нижче.

UPDATE tempDataView SET (marks) =
    (SELECT marks FROM tempData
     WHERE tempDataView.Name = tempData.Name);

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