我正在尝试创建一个具有表和参数的存储过程,并在该表上执行一些查询。
因此...
CREATE PROCEDURE blabla
@TableName nvarchar(50)
AS
DROP TABLE @TableName -- just an example, real queries are much longer
GO
此查询给出了错误的语法错误。
我知道我总是可以使用sp_executesql
程序,但我想要一个更简洁的方法,我不需要担心构建无限的sql字符串。
由于
答案 0 :(得分:4)
这是一篇很好的文章,说明为什么不在大多数情况下使用动态SQL,以及在最佳解决方案时如何正确使用它:
http://www.sommarskog.se/dynamic_sql.html
基本上,做你想做的事情有很多问题,包括不允许系统在执行前正确检查权限问题,不能优化存储过程,并且(最重要的是)打开自己SQL注入。您可以稍微缓解这个最后一个问题,但它涉及更复杂的语句。以下是上述文章的引用:
将表和列名称作为参数传递给具有动态SQL的过程对于应用程序代码来说很少是一个好主意。 (它对管理任务非常有意义)。正如我所说,您不能将表或列名作为参数传递给sp_executesql,但必须将其插入到SQL字符串中。作为常规问题,你应该保护它免受SQL注入。它可能会因用户输入而变坏。
为此,您应该使用内置函数quotename()(在SQL 7中添加)。 quotename()有两个参数:第一个是字符串,第二个是用于包装字符串的一对分隔符。第二个参数的默认值是[]。因此,引号('Orders')返回[Orders]。 quotename()负责嵌套分隔符,所以如果你有一个非常疯狂的表名如Left] Bracket,则quotename()将返回[Left]] Bracket]。
请注意,使用包含多个组件的名称时,应分别引用每个组件。 quotename('dbo.Orders')返回[dbo.Orders],但这是一个未知模式中的表,前四个字符是d,b,o和一个点。只要您只使用dbo架构,最佳做法是在动态SQL中添加dbo并仅传递表名。如果使用不同的模式,请将模式作为单独的参数传递。 (尽管您可以使用内置函数parsename()在部分中拆分@tblname参数。)
我知道你想要一种“整洁”的方式来创造一个动态的陈述,但现实是,不仅如此不可能你想要这样做,真的你需要使声明更复杂,以确保存储过程是安全的。我会非常努力地寻找一种不同的方法来解决这个问题(文章提出了一些建议)。如果你可以避免将这个语句变成动态SQL,你真的应该这样做。
答案 1 :(得分:1)
很少有地方可以在T-SQL中使用参数。通常,它恰好是您找到引用的字符串的地方 - 而不仅仅是查询中的任意位置(无论如何查询必须是字符串形式)
例如,您可以使用参数或变量替换下面的'hello'
:
SELECT * from Table2 where ColA = 'hello'
但是在Table2
出现的地方你无法使用它。我不知道为什么人们似乎期望在T-SQL中可以实现这样的事情,而在exec
/ eval
样式函数之外,大多数其他编程语言通常都不可能。
如果你有多个共享相同结构的表(列的名称和类型),那么通常表明你应该拥有的是一个单独的表,可能还有其他列区分原本位于不同表中的行。例如。如果你现在有:
CREATE TABLE MaleEmployees (
EmployeeNo int not null,
Name varchar(50) not null,
)
和
CREATE TABLE FemaleEmployees (
EmployeeNo int not null,
Name varchar(50) not null
)
你应该改为:
CREATE TABLE Employees (
EmployeeNo int not null,
Name varchar(50) not null,
Gender char(1) not null,
constraint CK_Gender_Valid CHECK (Gender in ('M','F'))
)
然后,无论性别如何,您都可以查询此Employees
表,而不是尝试在查询中参数化表名。当然,以上是一个夸张的例子。
答案 2 :(得分:0)
set @l = 'DROP TABLE ' + @TableName
exec @l
但如果你的意思是“无尽的弦”,那就不确定你想要什么了
答案 3 :(得分:-2)
正确的语法(注意开头):
CREATE PROCEDURE blabla
@TableName nvarchar(50)
AS
begin
DROP TABLE @TableName -- just an example, real queries are much longer
END
GO