动态SQL Server存储过程,表名为输入参数

时间:2014-10-10 11:46:53

标签: sql sql-server

我有以下存储过程

CREATE PROCEDURE [dbo].[Insert]
    @Service varchar(max),
    @TableName varchar(100),
    @Query varchar(250),
    @Results varchar(max),
    @CreatedDate datetime,
    @ExpirationDate datetime
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRANSACTION
        DECLARE @SQL NVARCHAR(MAX), @ParmDefinition NVARCHAR(MAX)
        DECLARE @q1 VARCHAR(MAX), @rez1 VARCHAR(MAX),  
                @date1 DATETIME, @date2 DATETIME

        DECLARE @tablename VARCHAR(MAX) = @Service + '.' + @TableName

        SET @SQL = N'if not EXISTS (select @q from ' + @tablename + ' where Query = @q) insert into ' + @tablename + ' values(@q, @rez, @date1, @date2)'

        SET @ParmDefinition = N'@q varchar(max), @rez varchar(max), 
                                @date1 datetime, @date2 datetime'

        EXECUTE sp_executeSQL      -- Dynamic T-SQL
            @SQL,
            @ParmDefinition,
            @q = @Query,
            @rez = @Results,
            @date1= @CreatedDate,
            @date2 = @ExpirationDate

        COMMIT TRANSACTION
END

当我尝试执行它时,它不会插入任何内容,0行

如果我在没有存储过程的情况下执行代码,就像单个查询一样,它会插入

我错过了什么吗?

1 个答案:

答案 0 :(得分:3)

你的问题中有很多事情对我没有任何意义,为什么你需要在你的程序中声明所有这些变量。

是的,你是使用参数化查询来保护自己免受sql注入攻击,但你通过连接对象名称(表和数据库名称)留下了一个漏洞,是的你需要连接它们但你可以使用{{1}它们周围的函数传递参数并强制执行sql server以在这些参数周围加上方括号,并强制sql server将它们视为对象名称。

选择QUOTENAME()中的变量没有多大意义。选择1,如果找到具有匹配条件的行,则返回true;如果未找到任何行,则只会插入一行。

只声明需要声明的变量,否则会使它看起来像一团糟,难以调试。正如他们所说IF EXISTS :)

同样为参数使用适当的数据类型Keep it simple我相信你的数据库名称为什么它需要是VARCHAR(MAX)数据类型,使用特定的数据类型来存储Sql Server对象名@Service 1}}。

SYSNAME