Создание операторов SQL UPDATE на лету

Я нахожусь в процессе обновления данных в нескольких таблицах. В настоящее время у меня есть таблица, которая имеет одно поле "sources", то есть просто список всех таблиц, которые включают поле "itemid". У меня также есть таблица, которая имеет 2 поля, "itemid" и "olditemid". В TSQL я хотел бы перебирать источники и создавать операторы обновления на лету. Вот что я пытался сделать, но я получаю некоторые ошибки в операторе обновления, что моя переменная не объявлена. Я не уверен, что это даже близко к правильному способу, которым я должен делать это. Идеи?

DECLARE @tblName varchar(50)

DECLARE process_cursor CURSOR FOR 
    SELECT source 
    FROM tmpTableNames

OPEN process_cursor

FETCH NEXT FROM processcursor 
INTO @tblName

WHILE @@FETCH_STATUS = 0

    UPDATE @tblName 
        SET itemid = r.itemid 
        FROM @tblName v, itemref r
        WHERE r.olditemid = v.itemid

    FETCH NEXT FROM process_cursor
    INTO @tblName

END
CLOSE processcursor
DEALLOCATE processcursor

5 ответов

Решение

То, что вы пытаетесь сделать, называется "динамический SQL". Пока вы на правильном пути, вы не можете просто вставить переменную вместо имени объекта и выполнить запрос. Я оставлю ловушки динамического SQL кому-то еще. То, что вы ищете, это:

DECLARE @tblName varchar(50)

DECLARE process_cursor CURSOR FOR 
    SELECT source 
    FROM tmpTableNames

OPEN process_cursor

FETCH NEXT FROM processcursor 
INTO @tblName

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @sql NVARCHAR(500)

    SELECT @sql = 'UPDATE [' + @tbleName + '] SET itemid = r.itemid FROM [' + @tbleName + '] v, itemref r WHERE r.ilditemid = v.itemid'

    EXEC sp_executesql @sql
    FETCH NEXT FROM process_cursor
    INTO @tblName

END
CLOSE processcursor
DEALLOCATE processcursor

Это превращает ваш запрос на обновление в строку, а затем передает SQL, содержащийся в этой строке, в sp_executesql хранимая процедура (это рекомендуемый способ выполнения динамического SQL, а не EXEC('foo')).

Я не думаю, что вы можете сделать это с помощью такой переменной. Вы можете использовать динамический SQL для обновления:

DECLARE @sql VARCHAR(1000)

SET @sql = 'UPDATE' + @tableName + etc..

EXEC ( @sql )

И просто сделай это внутри своего курсора.

Вы не можете выполнить sql динамически, как это - вам нужно передать динамически сгенерированную строку в функцию exec следующим образом:

DECLARE @tblName varchar(50)

DECLARE process_cursor CURSOR FOR 
    SELECT source 
    FROM tmpTableNames

OPEN process_cursor

FETCH NEXT FROM processcursor 
INTO @tblName

WHILE @@FETCH_STATUS = 0

    Declare @sql varchar(5000)
    Select @sql = 'UPDATE ' + @tblName +  
        'SET itemid = r.itemid 
        FROM ' + @tblName + ' v, itemref r
        WHERE r.olditemid = v.itemid'

    Exec @sql
    FETCH NEXT FROM process_cursor
    INTO @tblName

END
CLOSE processcursor
DEALLOCATE processcursor

Вы пробовали объявить @tblName varchar(50)? Я думаю, что это сделало бы это.

Я никогда не был успешным с основанными на переменных операторами UPDATE (то есть, UPDATE @tblName), если я не собрал их в строку и не выполнил их динамически, как в:

EXEC 'UPDATE ' + @tblName + '
SET ItemId = (SELECT r.ItemId FROM itemref r WHERE r.OldItemId = ' + @tblName + '.itemId)'

Для таблицы TheTable это должно быть расширено до:

EXEC 'UPDATE TheTable
      SET ItemId = (SELECT r.ItemId FROM itemref r WHERE r.OldItemId = TheTable.ItemId)'
Другие вопросы по тегам