Ski*_*eak 2 sql-server stored-procedures
我一直在研究一些具有条件参数的存储过程,但其中一个给我带来了一个我无法弄清楚的问题。这是程序的代码:
CREATE PROCEDURE dbo.GetTableData(
@TblName VARCHAR(50),
@Condition VARCHAR(MAX) = NULL,
) AS
BEGIN
IF(EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TblName))
BEGIN
DECLARE @SQL NVARCHAR(MAX) = N'
SELECT * FROM @TblName WHERE 1=1'
+ CASE WHERE @Condition IS NOT NULL THEN
' AND ' + @Condition ELSE N'' END
DECLARE @params NVARCHAR(MAX) = N'
@TblName VARCHAR(50),
@Condition VARCHAR(MAX)';
PRINT @SQL
EXEC sys.sp_executesql @SQL, @params,
@TblName,
@Condition
END
ELSE
RETURN 1
END
Run Code Online (Sandbox Code Playgroud)
我希望程序工作的方式是,它允许我进行快速的表查找。因此,如果我想查看 Parts 表中的所有内容,我只需运行
EXEC GetTableData 'parts'
Run Code Online (Sandbox Code Playgroud)
或者,如果我想查看零件表中的所有内容,我会运行特定的供应商
EXEC GetTableData 'parts', 'supplier LIKE ''A2A Systems'''
Run Code Online (Sandbox Code Playgroud)
现在在上面的示例中,当我运行它时,该PRINT @SQL
行将查询打印为:
SELECT * FROM @TblName WHERE 1=1 AND supply LIKE 'A2A Systems'
所以查询它被正确地放在一起(似乎)。
但是在打印后,我收到以下错误:
消息 1087,级别 16,状态 1,第 4 行
必须声明表变量“@TblName”
如果我将EXEC
行更改为:
EXEC GetTableData @TblName='parts', @Condition='supplier LIKE ''A2A Systems'''
Run Code Online (Sandbox Code Playgroud)
那么我在这里做错了什么?为什么不取我的@TblName
变量值?
您不能参数化实体名称(表、列、视图等)。你需要以更危险的方式做到这一点:
DECLARE @SQL NVARCHAR(MAX) = N'
SELECT * FROM ' + QUOTENAME(@TblName) + N' WHERE 1=1'
+ CASE WHERE @Condition IS NOT NULL THEN
' AND ' + @Condition ELSE N'' END
DECLARE @params NVARCHAR(MAX) = N'
@Condition VARCHAR(MAX)';
PRINT @SQL
EXEC sys.sp_executesql @SQL, @params,
@Condition
Run Code Online (Sandbox Code Playgroud)
QUOTENAME()
通常足以防止危险的执行(可能导致 SQL 注入),但为了使其更安全,您应该考虑(a)使用正确的模式前缀作为表名的前缀(例如...FROM dbo.' + QUOTENAME(@TblName) + ...
和(b)检查是否存在)第一的:
IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = @TblName)
BEGIN
RAISERROR(N'Nice try, robot.', 11, 1);
RETURN;
END
DECLARE @SQL ...
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
25014 次 |
最近记录: |