2012-04-15 72 views
0

您好我正在尝试运行下面的SQL,它将通过遍历所有名称为“Pull”的数据库来提取名为SourceDestination的表名。sp_executesql中的语法错误

但是我在'[email protected]_name+'.sys.tables附近的加号出现错误。我在两边尝试了N',但我似乎无法让它工作。

它给出了这个错误 Msg 102,Level 15,State 1,Line 20 '+'附近语法不正确。

需要知道我错在哪里。谢谢您的帮助。

declare db_names cursor for 
select name 
from master.sys.databases 
where name like 'Pull_%' 

declare @db_name varchar(50) 
declare @table_name varchar(50) 
declare @sql nvarchar(100) 
DECLARE @ParmDefinition NVARCHAR(500); 
open db_names 

fetch next from db_names into @db_name 

while @@FETCH_STATUS = 0 
begin 
print @db_name 

    -- set @sql = 'select '[email protected]_name+'=name from '[email protected]_name+'.sys.tables' 
    -- set @sql = N'select @table_name=name from @db_name.sys.tables where name = ''SourceDestinations'' ' 
execute sp_executesql N'select @tbl_name=name from '[email protected]_name+'.sys.tables where name = ''SourceDestinations'' ', N'@tbl_name varchar(50) OUTPUT', @[email protected]_name OUTPUT 
--exec(@sql)o 
print @table_name 
FETCH NEXT FROM db_names INTO @db_name 
    end 

    close db_names 
    deallocate db_names 

回答

2

需要构建命令字符串作为来自sp_executesql呼叫一个单独的步骤:

set @sql = N'select @tbl_name=name from '[email protected]_name+'.sys.tables where name = ''SourceDestinations'' ' 
execute sp_executesql @sql, N'@tbl_name varchar(50) OUTPUT', @[email protected]_name OUTPUT 

EDIT 变量可以不被第二次迭代设置。
尝试增加

SET @table_name = NULL 

print @table_name 
+0

非常感谢!现在没有引发语法错误。但我还有一个问题。游标返回两个数据库名称,但sys.tables上的查询仅适用于返回的第一个数据库名称。对于第二个DB名称,返回前一个DB本身的结果。我添加了一个调试,它显示@db_name变量包含每个迭代的每个数据库的名称,但两个数据库名称的结果相同。 – JunaidKirkire 2012-04-15 13:04:04

+0

@JunaidKirkire - 将查询写入(假设表中的'SourceDestinations'出现在两个数据库中),您将得到两个查询相同的结果。请修改问题以更新您的当前查询,并更详细地描述您要实现的内容。 – 2012-04-15 13:33:52

+0

表格SourceDestinations不存在于第二个数据库中。它仍然显示db_name的第二个值。在sys.tables上运行查询之前,我做了'use'+ db_name。尽管如此,表格'SourceDestinations'被返回。 我以调试模式运行查询,只是为了确保db_name具有第二个数据库的名称。 我想要实现的是遍历所有在其名称中具有'Pull'并查询某些表的数据库。 但是,它似乎只有第一个数据库被查询。 – JunaidKirkire 2012-04-15 14:02:16

0

如果你想要做的就是打印数据库表中的名字,你的脚本可以更简单(我不明白这一点检索表名和每一次打印出来的 - 什么不可能是其他比SourceDestinations):

DECLARE @sql NVARCHAR(MAX); 
SET @sql = N''; 

SELECT @sql = @sql + 'IF EXISTS (SELECT 1 FROM ' + QUOTENAME(name) 
    + '.sys.tables WHERE name = ''SourceDestinations'') 
    PRINT ''' + name + ''';' 
FROM sys.databases 
WHERE name LIKE 'PULL_%'; 

EXEC sp_executesql @sql; 

我怀疑,虽然你想做的事莫?一旦确定了实际表格的存在位置,请重新确定。 Ed是绝对正确的,你不能在你执行的时候连接一个字符串到sp_executesql中,你必须事先建立它。所有存储过程调用都是如此,例如你不能说:

EXEC sp_who2 'act' + 'ive'; 

即使它应该是同样的事情:

EXEC sp_who2 'active'; 

你似乎已经知道了这一点,至少在一定程度上,因为你声明的变量@sql(尽管你从不使用它)。

我想你的代码更改为:

DECLARE d CURSOR 
    LOCAL STATIC FORWARD_ONLY READ_ONLY 
    FOR SELECT name FROM sys.databases 
    WHERE name LIKE 'Pull_%'; 

DECLARE 
    @db_name NVARCHAR(128), 
    @sql  NVARCHAR(MAX); 

OPEN d; 

FETCH NEXT FROM d INTO @db_name; 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    PRINT @db_name; 

    SET @sql = N'IF EXISTS (SELECT 1 FROM ' + QUOTENAME(@db_name) 
    + '.sys.tables WHERE name = ''SourceDestinations'') 
     PRINT ''' + @db_name + ''';' 

    EXEC sp_executesql @sql; 

    FETCH NEXT FROM d INTO @db_name; 
END 

CLOSE d; 
DEALLOCATE d; 

几个关键点:

  1. 不要使用默认光标选项。在这种情况下,这可能不是一个大问题,但这是一个不好的习惯。我在本博文中突出显示了一个性能影响的案例:http://sqlblog.com/blogs/aaron_bertrand/archive/2011/03/08/t-sql-tuesday-16-this-is-not-the-aggregate-you-re-looking-for.aspx
  2. 请勿将varchar(50)用于数据库/表名。根据标识符的规则(this doc is from 2000,但是similar docs exist for newer versions),这些应该是nvarchar(128)
  3. 你也应该检查模式。如果有人无意中在他们自己的默认模式中创建了一个,你可能会得到多个SourceDestinations
  4. 您的@sql字符串应该可能超过100个字符。在这些情况下,我通常使用MAX,因为性能差异不值得坐在那里,想知道255或1024等是否会有足够的字符。