Обновить запрос с использованием подзапроса на сервере Sql

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столбец marksвключения в обеих таблицах.

с помощью SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )
Джон Ву
источник
1
это правильно. но, пожалуйста, предложите мне способ сделать это с помощью подзапроса.
Narendra Pal
1
обновил ответ subquery, но я предпочитаю использовать JOINчем SUBQUERY.
Джон Ву
1
Зачем определим INDEXпо marksстолбцам? Разве не на Nameколоннах?
lindelof
1
Получена ошибка: подзапрос вернул более одного значения. Это не разрешено, если подзапрос следует за =,! =, <, <=,>,> = Или когда подзапрос используется как выражение.
Pradip
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. Для таблицы a у вас есть ответ, предоставленный 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 Fiddle, созданный 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 просто попробуйте - на любой таблице, в которой есть записи. например. выберите количество (*) из журнала событий, где год = 2018
Грэм Лэйт
Итак, вы просто считаете всю таблицу. Я поддерживаю свой голос против, это не имеет ничего общего с вопросом (независимо от названия)
crthompson
Это ваша прерогатива, но название этой ветки - «запрос на обновление с использованием подзапроса», и мой пример, очевидно, делает именно это. fyi, я не считаю «всю таблицу» - за count (*) следует предложение «where» - так что подсчет строк соответствует условию «where».
Грэм Лэйт,
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 не является уникальным ключом, тогда как первый запрос гарантированно вызовет ошибку, если есть несколько совпадений идентификаторов. Кроме того, если для конкретной записи account.sales_id нет совпадения, первый запрос установит для соответствующих полей имени значение NULL, тогда как второй запрос вообще не обновит эту строку.

Следовательно, для данного примера наиболее надежный запрос выглядит следующим образом.

UPDATE tempDataView SET (marks) =
    (SELECT marks FROM tempData
     WHERE tempDataView.Name = tempData.Name);
Memin
источник
К сожалению, первая форма не работает на сервере MS SQL.
AntoineL