2012-04-15 58 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等是否會有足夠的字符。