2017-01-17 9 views
0

Я не понимаю, почему я продолжаю получать эту ошибку. Любой может помочь мне понять, почему эта ошибка подходит, будет очень признательна. Я пытаюсь обновить большую базу данных и попытаться заменить строку местоположения по умолчанию для всех вложений с помощью «D:». Я чувствую, что я рядом, но я не понимаю эту ошибку. Этот запрос успешно проходит через все мои имена таблиц, сохраненные в @Tables, но на каждом из них я получаю ошибку. Вот мой код ... Ошибка: Необходимо объявить скалярную переменную «@oldPath»Должен объявить скалярную переменную

DECLARE @newPath VARCHAR(500); 
SET @newPath = 'D:\temp'; 

DECLARE @oldPath VARCHAR(500); 
SET @oldPath = (SELECT Value FROM Settings WHERE Name = 'AttachmentDirectoryPath'); 



DECLARE @Tables TABLE 
(
    myTableName VARCHAR(500) 
) 

insert into @Tables(myTableName) values ('WorkOrderMasterAttachments'); 
insert into @Tables(myTableName) values ('BillOfMaterialAttachments'); 
insert into @Tables(myTableName) values ('CustomerAttachments'); 
insert into @Tables(myTableName) values ('ToolAttachments'); 
insert into @Tables(myTableName) values ('FacilityAttachments'); 
insert into @Tables(myTableName) values ('LocationAttachments'); 
insert into @Tables(myTableName) values ('AssetAttachments'); 
insert into @Tables(myTableName) values ('ContractorAttachments'); 
insert into @Tables(myTableName) values ('VendorAttachments'); 
insert into @Tables(myTableName) values ('WorkOrderAttachments'); 
insert into @Tables(myTableName) values ('ClosedWorkOrderAttachments'); 
insert into @Tables(myTableName) values ('EmployeeAttachments'); 
insert into @Tables(myTableName) values ('PurchaseOrderAttachments'); 
insert into @Tables(myTableName) values ('PurchaseOrderHistoryAttachments'); 
insert into @Tables(myTableName) values ('PartAttachments'); 
insert into @Tables(myTableName) values ('AssetSystemAttachments'); 

DECLARE cursor_tables cursor 
FOR SELECT myTableName from @Tables 

OPEN cursor_tables 

DECLARE @loopTableName VARCHAR(100) 

fetch next from cursor_tables 
into @loopTableName 

DECLARE @updateSql VARCHAR(2000); 

WHILE @@FETCH_STATUS = 0 
BEGIN 

    SET @updateSql = ' UPDATE ' + @loopTableName + 
       ' SET Path = REPLACE(Path,@oldPath,@newPath)' 

    --print @updateSql 
    EXEC(@updatesql) 

    fetch next from cursor_tables 
    into @loopTableName 
END 

CLOSE cursor_tables 
DEALLOCATE cursor_tables 
+0

Разве это не было бы проще просто написать свои заявления об обновлении 15-16 вместо того, чтобы делать это в цикле? Было бы намного меньше печатать, и это было бы намного проще. –

+0

Да, но я буду загружать @ Таблицы со всеми таблицами с именами LIKE '% Attachments%' вместо всех операторов insert. – techkris

+0

Даже если вы используете динамический sql, я бы не использовал для этого цикл. Используйте динамический sql для сборки операторов sql и выполните его все сразу. –

ответ

2

Использование SP_EXECUTESQL для передачи значений переменных внутри динамического запроса

DECLARE @updateSql NVARCHAR(2000) -- important 

SET @updateSql = ' UPDATE ' + QUOTENAME(@loopTableName) + 
      ' SET Path = REPLACE(Path,@oldPath,@newPath)' 

--print @updateSql 
EXEC sp_executesql @updatesql, 
    N'@oldPath VARCHAR(500),@newPath VARCHAR(500)', 
     @oldPath = @oldPath, @newPath = @newPath 

sp_executesql требует @stmt параметр, чтобы быть NVARCHAR, измените тип данных @updateSql от VARCHAR до NVARCHAR

1

Строки не автоматические kn что они содержат переменные. Итак, забудьте о EXEC() как общий метод для выполнения динамического SQL. Помните: sp_executesql вместо этого сделать внутренний цикл:

SET @updateSql = ' UPDATE ' + @loopTableName + 
      ' SET Path = REPLACE(Path, @oldPath, @newPath)' 

exec sp_executesql @updatesql, 
    N'@oldPath varchar(500), @newPath varchar(500)', 
    @oldPath = @oldPath, @newPath = @newPath; 

Это будет выполнять SQL и назначить переменные. Примечание. Вы не можете передать имя таблицы в качестве параметра в запрос, поэтому вам все равно нужно предоставить это непосредственно в строке.

1

Вот гораздо более простой подход, чем использование цикла для того, что, скорее всего, не то, что вам нужно запускать очень часто.

DECLARE @newPath VARCHAR(500) = 'D:\temp'; 

DECLARE @oldPath VARCHAR(500); 
SELECT @oldPath = Value 
FROM Settings 
WHERE Name = 'AttachmentDirectoryPath' 

update WorkOrderMasterAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update BillOfMaterialAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update CustomerAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update ToolAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update FacilityAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update LocationAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update AssetAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update ContractorAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update VendorAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update WorkOrderAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update ClosedWorkOrderAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update EmployeeAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update PurchaseOrderAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update PurchaseOrderHistoryAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update PartAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 
update AssetSystemAttachments SET Path = REPLACE(Path, @oldPath, @newPath) 

--EDIT--

Так как вы заявили, что вы действительно хотите использовать таблицу, чтобы получить все имена таблиц обновлять здесь подход с использованием динамического SQL, который не нуждается в петле. Он создает длинную строку операторов sql для обновления каждой таблицы, но не использует цикл. Я понимаю, что производительность 15-16 итераций не так много, но этот пример - способ избежать циклов, и, на мой взгляд, намного проще отлаживать код. Это также для меня концептуализировать этот тип вещи вместо использования цикла.

DECLARE @Tables TABLE 
(
    myTableName VARCHAR(500) 
) 

insert into @Tables(myTableName) values ('WorkOrderMasterAttachments'); 
insert into @Tables(myTableName) values ('BillOfMaterialAttachments'); 
insert into @Tables(myTableName) values ('CustomerAttachments'); 
insert into @Tables(myTableName) values ('ToolAttachments'); 
insert into @Tables(myTableName) values ('FacilityAttachments'); 
insert into @Tables(myTableName) values ('LocationAttachments'); 
insert into @Tables(myTableName) values ('AssetAttachments'); 
insert into @Tables(myTableName) values ('ContractorAttachments'); 
insert into @Tables(myTableName) values ('VendorAttachments'); 
insert into @Tables(myTableName) values ('WorkOrderAttachments'); 
insert into @Tables(myTableName) values ('ClosedWorkOrderAttachments'); 
insert into @Tables(myTableName) values ('EmployeeAttachments'); 
insert into @Tables(myTableName) values ('PurchaseOrderAttachments'); 
insert into @Tables(myTableName) values ('PurchaseOrderHistoryAttachments'); 
insert into @Tables(myTableName) values ('PartAttachments'); 
insert into @Tables(myTableName) values ('AssetSystemAttachments'); 

declare @SQL nvarchar(max) = '' 

select @SQL = @SQL + 'Update ' + myTableName + ' set Path = REPLACE(Path,@oldPath,@newPath);' 
from @Tables 

select @SQL 

exec sp_executesql @SQL, N'@oldPath varchar(500), @newPath varchar(500)', @oldPath = @oldPath, @newPath = @newPath 
+0

Это интересно. Мне это нравится и, вероятно, будет использовать это вместо цикла. Я в конечном итоге загрузки @Tables с этим: INSERT INTO @Tables (myTableName) \t ВЫБОРА TABLE_NAME ОТ INFORMATION_SCHEMA.TABLES \t ГДЕ table_name LIKE '% Вложение%' – techkris

+0

Вы можете пропустить переменные таблицы целиком и просто использовать sys.tables. Я надеюсь, вы включите схему в свой код. И если это так, вы не должны использовать INFORMATION_SCHEMA.TABLES для определения схемы. https://msdn.microsoft.com/en-us/library/ms186224.aspx –

Смежные вопросы