【问题标题】:Using dynamic sql in a procedure to insert data into schema tables在过程中使用动态 sql 将数据插入模式表
【发布时间】:2019-03-18 11:34:15
【问题描述】:

希望你们一切都好。

我一直在做一个项目,我需要存储关于我的大学的数据,包括身份证号码、姓名、联系方式等。

我在创建能够将数据插入指定 schema.table_name 的存储过程时遇到了一些困难。该过程必须能够允许 EXEC 命令指定您希望将数据插入到哪个模式。对于所有 14 个模式,table_name 将保持不变。以下代码示例是我想出的,但它似乎不起作用:

CREATE PROCEDURE AddStudent_proc(@campus varchar(50), @StudentID numeric(4,0), @Name varchar(50), @Surname varchar(50), @ID_numeric numeric(13,0), @Address varchar(100))
AS
BEGIN
    DECLARE @dynamic varchar(MAX)
    SET @dynamic = 'INSERT INTO ['+quotename(@campus)+'].Student_tbl(
    StudentID,
    Name,
    Surname,
    ID_numeric,
    Address
    )
    VALUES('+quotename(@StudentID)+','+quotename(@Name)+','+quotename(@Surname)+','+quotename(@ID_numeric)+','+quotename(@Address)+');'
    EXEC (@dynamic);
END
GO

可以找到我的整个结构 here

如果我对这个主题有任何帮助,我将不胜感激,因为我对整个 SQL 还是很陌生。

提前致谢。

【问题讨论】:

  • 您需要在动态查询中进行适当的引用。我总是在执行之前选择语句。选择@dynamic --> EXEC (@dynamic) 找出问题所在。每个级别都需要双引号。

标签: sql-server tsql stored-procedures dynamic-sql


【解决方案1】:

您不需要将quotename 用于数据 - 正如函数名称所暗示的那样,它应该与名称(A.K.A 标识符)一起使用。
此外,当您使用quotename 时,它会在收到的值周围添加[],因此无需再次添加它们(代码中的['+quotename(@campus)+'])。

我建议对您现在的程序进行三项改进:

  1. @campus 的数据类型更改为sysname - 这是SQL Server 用于所有标识符的nvarchar(128) not null 的特殊数据类型同义词。
  2. 将架构名称列入白名单。
    这是防止 SQL 注入攻击的关键更改。
    任何无法参数化的东西都需要列入白名单。
  3. 使用sp_ExecuteSql 而不是EXEC

这将产生更好的存储过程,因为它消除了SQL Injection 的威胁:

CREATE PROCEDURE AddStudent_proc(
    @campus sysname, 
    @StudentID numeric(4,0), 
    @Name varchar(50), 
    @Surname varchar(50), 
    @ID_numeric numeric(13,0), 
    @Address varchar(100)
)
AS
BEGIN

    IF EXISTS(
        SELECT 1
        FROM Sys.Schemas
        WHERE name = @campus
    )
    BEGIN

    DECLARE @dynamic nvarchar(4000), 
            @paramDefinition nvarchar(4000)


        SELECT @dynamic = N'INSERT INTO '+ quotename(@campus) + N'.Student_tbl (
            StudentID,
            Name,
            Surname,
            ID_numeric,
            Address
        )
        VALUES(@StudentID, @Name, @Surname, @ID_numeric, @Address)',
        @paramDefinition = 
          N'@StudentID numeric(4,0), 
            @Name varchar(50), 
            @Surname varchar(50), 
            @ID_numeric numeric(13,0), 
            @Address varchar(100)'

        EXEC sp_executeSql @dynamic, @paramDefinition, @StudentID, @Name, @Surname, @ID_numeric, @Address;
    END
END
GO

【讨论】:

  • 谢谢,它按预期完美运行。只是一个用于学习目的的快速问题,INSERT INTO 之前的“N”有什么用?
  • 再次感谢。很有帮助。
  • 我已经编辑了我的答案,又做了一个更改 - 不是非常重要,但很高兴知道。很高兴帮助:-)
  • @ZoharPeled:我知道。也许只是个人经验,但我无法计算开发人员看到没有详细解释注入缺陷的博客或 SO 帖子的次数,并决定 DECLARE @ SQL = 'SELECT * FROM ' + @Table; sp_executesql @SQL 没问题。另外,不错的更新。它包罗万象。
猜你喜欢
  • 2023-03-07
  • 1970-01-01
  • 2019-08-05
  • 2020-07-05
  • 2017-01-26
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 2018-03-14
相关资源
最近更新 更多