2009-09-09 5 views
1

Я занимаюсь обновлением данных в нескольких таблицах. В настоящее время у меня есть таблица, в которой есть одно поле, «источники», это всего лишь список всех таблиц, которые включают поле «itemid». У меня также есть таблица с двумя полями, «itemid» и «olditemid». В TSQL я хотел бы перебирать источники и создавать инструкции обновления на лету. Вот что я пытался сделать, но я получаю некоторые ошибки в инструкции обновления, что моя переменная не объявлена. Я не уверен, что это даже близко, я должен это делать. Идеи?Создание операторов SQL UPDATE «на лету»

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 
+0

@tblName должно быть типа 'sysname', которое является правильным типом и длиной для имен объектов. varchar (50) слишком короткий для некоторых объектов, а имена таблиц могут содержать символы Unicode. –

ответ

4

То, что вы пытаетесь сделать, называется «динамическим 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')).

+0

Вы всегда должны использовать QUOTENAME для обертывания имен объектов, таких как таблица, в соответствующие '[' и ']' скобки. –

+0

@Remus: Хорошая добыча. Исправленный. –

0

пытались ли вы DECLARE @tblName VARCHAR (50)? Я бы подумал, что это сделаю.

+0

Я объявил это вверху. – SDC

+0

Возможно, вы пропустили декларацию в неформатированном коде. –

3

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

DECLARE @sql VARCHAR(1000) 

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

EXEC (@sql) 

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

0

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

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

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

EXEC 'UPDATE TheTable 
     SET ItemId = (SELECT r.ItemId FROM itemref r WHERE r.OldItemId = TheTable.ItemId)' 
1

вы не можете выполнить 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 

    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