2011-07-29 80 views
6

讓我們說我有這樣的查詢:有沒有辦法將表名指定爲字符串?

SELECT * FROM 
(
    SELECT * FROM 
    (
    SELECT * FROM DB.dbo.Table 
) 
    INNER JOIN DB.dbo.Table ON ... 

我通過手動改變無處不在的字符串不同的表多次運行此查詢。我試着聲明如下:

DECLARE @tablename AS VARCHAR(255) 
SET @tablename = 'DB.dbo.Table' 

但是,這似乎並沒有工作,因爲它引發了我的錯誤,說我需要聲明@tablename作爲表變量之前,我可以使用它。我如何模擬我的表名,如果可能的話,Intellisense是否仍然有效?

回答

7

您可以在這樣一個EXEC語句把它包:

declare @my_tablename nvarchar(100) = 'mytable'; 
exec(' 
SELECT * FROM 
(
    SELECT * FROM 
    (
    SELECT * FROM ' + @my_tablename + ' 
) 
    INNER JOIN ' + @my_tablename + ' ON ...' 
); 

不過沒有關係,智能感知不會在那種情況下工作。

如果您事先知道輸出結果的樣子,那麼您可以聲明一個臨時表來保存結果,然後您可以在沒有EXEC的情況下訪問它。您將在臨時表上有智能感知。

例如:

--this must match whatever your SELECT is going to return 
    CREATE TABLE #results(
    FIELD1 INT 
    ,FIELD2 NVARCHAR(100) 
    ,FIELD3 BIT 
    ); 

EXEC(' 
    INSERT INTO #results(field1,field2,field3) 
    SELECT FIELD1,FIELD2,FIELD3 FROM ' + @my_tablename 
); 

select * from #results --you will have intellisense on #results 
3

您使用動態SQL。不知道你爲什麼需要這麼多的嵌套的SELECT,但它會是這樣的:

DECLARE @sql NVARCHAR(MAX) = N'SELECT ... FROM ' + @tablename + '...'; 
EXEC sp_executeSQL @sql; 

但是請注意SQL注入。不,IntelliSense沒有能力爲對象名稱解析字符串(或者甚至在編輯對象名稱時將會知道)。

+0

+1。感謝您提及依賴注入。 –

4

No.就像你不能在c#程序中以字符串的形式指定函數名一樣。 T-SQL編譯應該提供精確的訪問計劃,這意味着要打開和使用哪些索引來滿足查詢。想出一個'字符串'的計劃是不可能的,就像在C#中不可能生成代碼來調用'字符串'作爲方法一樣。

的解決方案是動態SQL:

declare @sql NVARCHAR(MAX) = N'SELECT ... FROM ' + 
    quotename(@dbname) + N'.' + quotename(@schema) + N'.' + quotename(@table) + 
    N' WHERE ...'; 
exec sp_executesql @sql; 

...就像在C#中你可以使用反射來進行動態的運行時調用。

欲瞭解更多信息,請參閱The Curse and Blessings of Dynamic SQL

PS。將@tablename拆分爲組件,並且使用QUOTENAME是絕對必須的,它會防範agaisnt SQL注入。使用PARSENAME爲你做分割。

+0

爲鏈接+1,它總是處理動態SQL時首先要去的地方 – Lamak

相關問題