2011-07-29 77 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

相关问题