Проблема с вложенным курсором в SQL Server - PullRequest
1 голос
/ 08 декабря 2010

У меня странная проблема с моими вложенными курсорами, и я понятия не имею, о чем все это.

Вот мой код T-SQL:

declare @dbname varchar(50)
declare @servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare @str varchar(200)

truncate table test.dbo.temp

open srv
fetch next from srv into @servername
while @@fetch_status = 0   
begin   
   set @str = 'Data Source='+@servername+';Integrated Security=SSPI'   
   declare db cursor for select name from opendatasource('SQLNCLI', @str).master.dbo.sysdatabases
   open db
   fetch next from db into @dbname
   while @@fetch_status = 0
   begin
      insert test.dbo.temp (dbname, servername) values (@dbname, @servername)
      fetch next from db into @dbname
   end
   fetch next from srv into @servername
   close db
   deallocate db
end   
close srv
deallocate srv

Это дает мне следующее сообщение об ошибке:

Неверный синтаксис рядом с @str.[SQLSTATE 42000] (Ошибка 102)

Похоже, проблема в том, что переменная является параметром для функции opendatasource.Но почему?И как избежать этой проблемы?

Ответы [ 2 ]

3 голосов
/ 08 декабря 2010

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

declare @dbname varchar(50)
declare @servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare @str varchar(200)
declare @sql nvarchar(MAX)

truncate table test.dbo.temp

open srv
fetch next from srv into @servername
while @@fetch_status = 0   
begin
   SET @sql = N'
   declare db cursor for select name from opendatasource(''SQLNCLI'', ''Data Source='+@servername+';Integrated Security=SSPI'').master.dbo.sysdatabases
   open db
   fetch next from db into @dbname
   while @@fetch_status = 0
   begin
      insert test.dbo.temp (dbname, servername) values (@dbname, @servername)
      fetch next from db into @dbname
   end
   close db
   deallocate db
   '
   EXEC sp_executesql
    @sql,
    N'@dbname     varchar(50),
      @servername varchar(50)',
    @dbname,
    @servername

   fetch next from srv into @servername
end   
close srv
deallocate srv
1 голос
/ 08 декабря 2010

Если вам нужно использовать вложенные курсоры, вы делаете что-то не так.Существует очень мало причин использовать курсор вместо какой-либо другой операции, основанной на множестве, и использование курсора внутри курсора похоже на конечный анти-шаблон SQL Server.

Для внутреннего курсора вы можете изменить егоиспользовать недокументированную sp_msforeachdb функцию (которая, по-видимому, создает курсор за кулисами) :

open srv
fetch next from srv into @servername
while @@fetch_status = 0   
begin
 EXEC sp_msforeachdb '
 Data Source='+@servername+';Integrated Security=SSPI
 insert test.dbo.temp (dbname, servername) values (?, @Servername)'
 fetch next from srv into @servername
end   
close srv
deallocate srv

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

EXEC sp_msforeachdb 'insert test.dbo.temp (dbname, servername) values (''?'', @Servername)

...