2010-12-08 47 views
1

J'ai un problème étrange avec mes curseurs imbriqués et je n'ai aucune idée de quoi il s'agit.Problème de curseur imbriqué SQL Server

Voici mon code 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='[email protected]+';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 

Il me donne message d'erreur suivant:

syntaxe incorrecte près 'de @str'. [SQLSTATE 42000] (erreur 102)

dirait que le problème est en donnant la variable en tant que paramètre de fonction OpenDataSource. Mais pourquoi? Et comment éviter ce problème?

+4

* curseur imbriqué *: c'est votre problème là !! –

+2

@marc_s Je pense qu'un curseur imbriqué est la seule façon viable de faire ce que l'OP veut faire (faire défiler toutes les bases de données dans une collection de serveurs, dont les noms sont contenus dans une table) –

Répondre

3

Vous avez raison: les variables ne peuvent pas être passées à OPENDATASOURCE. Au lieu de cela, vous devez utiliser un littéral à la place. Autant que nous déconseillons l'utilisation de SQL dynamique, il y a des cas où c'est inévitable. Essayez quelque chose comme ceci:

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='[email protected]+';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

Merci beaucoup! Je n'ai pas pensé comme ça! :) c'est vraiment aidé! – stee1rat

+0

Vous êtes les bienvenus! –

2

Si vous devez utiliser des curseurs imbriqués, vous faites quelque chose de mal. Il y a très peu de raisons d'utiliser un curseur au lieu d'une autre opération basée sur un ensemble, et l'utilisation d'un curseur dans un curseur est comme l'anti-pattern SQL Server ultime.

Pour votre curseur intérieur, vous pouvez changer d'utiliser la fonction non documentée sp_msforeachdb(qui crée apparemment un curseur dans les coulisses):

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

Vous devrez peut-être joindre la? entre guillemets simples et leur échapper, comme:

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

+2

er, je suppose que vous n'avez pas regardé la définition de 'sp_msforeachdb' alors? (Il utilise un curseur!) –

+0

@Martin - lol Je ne savais pas comment ça fonctionnait en interne. Merci pour l'info. – JNK

+0

@JNK - Je suppose qu'il peut y avoir un argument pour l'utiliser quand même (+1). Cela enlève une partie de la complexité du code OP et fait des vérifications supplémentaires pour que la base de données soit accessible. –