0

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

但是我在'+@db_name+'.sys.tables 附近的加号处遇到错误。我在两边都试过 N'' 但我似乎无法让它工作。

它给出了这个错误消息 102,级别 15,状态 1,第 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
4

2 回答 2

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
于 2012-04-15T10:11:30.860 回答
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)用于数据库/表名。这些应该nvarchar(128)根据标识符的规则
  3. 此外,您还应该检查架构。SourceDestinations如果有人无意中在他们自己的默认架构中创建了一个,您可能会获得多次点击。
  4. 您的@sql字符串可能应该超过 100 个字符。我通常MAX在这些情况下使用,因为性能差异不值得坐在那里想知道 255 或 1024 等是否足够字符。
于 2012-04-15T20:54:05.350 回答