sp_executesql中的语法错误

时间:2012-04-15 09:50:45

标签: sql sql-server

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

但是我在'+@db_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 '+@table_name+'=name from '+@db_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 '+@db_name+'.sys.tables where name = ''SourceDestinations'' ', N'@tbl_name varchar(50) OUTPUT', @tbl_name=@table_name OUTPUT
--exec(@sql)o
print @table_name
FETCH NEXT FROM db_names INTO @db_name
    end

    close db_names
    deallocate db_names

2 个答案:

答案 0 :(得分:2)

您需要将命令字符串构建为sp_executesql调用的单独步骤:

set @sql = N'select @tbl_name=name from '+@db_name+'.sys.tables where name = ''SourceDestinations'' '
execute sp_executesql @sql, N'@tbl_name varchar(50) OUTPUT', @tbl_name=@table_name OUTPUT

修改 第二次迭代可能没有设置变量 尝试添加

SET @table_name = NULL

print @table_name

答案 1 :(得分: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. 请勿使用默认光标选项。在这种情况下,它可能不是一个大问题,但它是一个坏习惯进入。我在此博客文章中强调了一个性能影响案例:https://sqlblog.org/2011/03/08/t-sql-tuesday-16-this-is-not-the-aggregate-youre-looking-for
  2. 不要将varchar(50)用于数据库/表名。根据{{​​3}},这些应为nvarchar(128)
  3. 此外,您还应该检查架构。如果有人无意中在自己的默认架构中创建了一个点击,您可能会获得SourceDestinations的多次点击。
  4. 您的@sql字符串可能超过100个字符。我通常在这些情况下使用MAX因为性能差异不值得坐在那里想知道255或1024等是否足够。