【问题标题】:Issues encountered with dynamic SQL动态 SQL 遇到的问题
【发布时间】:2020-05-07 22:31:17
【问题描述】:
ALTER PROCEDURE [dbo].[Create_Subjects]
    @Subj_ID nvarchar(9)
AS
    DECLARE @First3Digits nvarchar(3);
    DECLARE @Result int;
    DECLARE @Sql nvarchar(max)

    -- Fetching the fiest 3 digits of the subject
    SET @First3Digits = SUBSTRING(@Subj_ID,1,3);

    -- Check if view is present or not
    IF EXISTS (SELECT 1 FROM sys.views WHERE Name = @First3Digits)
    BEGIN
        SET @Sql = 'select @Result = case when exists (select 1 from dbo.' + quotename(@First3Digits) + ' where SubjectName = ''' + @Subj_ID + ''') then 1 else 0 end';
        EXECUTE sp_executesql @Sql, N'@Subj_ID nvarchar(9), @Result bit out', @Subj_ID = @Subj_ID, @Result = @Result out; 
        -- checking if the subject is present in the view    
    END
    ELSE
    BEGIN
        -- Create a view as view doesn't exist
        SET @Sql = 'create view ' + @First3Digits 
                    + ' as 
    (select SubjectName from dbo.Subjects where SubjectName like '+@First3Digits+'%'+');';
        EXECUTE sp_executesql @Sql, N'@First3Digits nvarchar(3)', @First3Digits= @First3Digits;
        SET @Result = 0;
    END

    RETURN @Result
GO

这是执行存储过程的代码:

EXEC [dbo].[Create_Subjects] '1234567890'

遇到错误:

消息 156,第 15 级,状态 1,第 28 行
关键字“view”附近的语法不正确

消息 102,第 15 级,状态 1,第 29 行
')' 附近的语法不正确

【问题讨论】:

  • 这是create view语句的语法
  • Msg 156, Level 15, State 1, Line 28 关键字“view”附近的语法不正确。消息 102,级别 15,状态 1,第 29 行 '%' 附近的语法不正确。
  • 如果您的视图名称不符合常规标识符命名规则(例如,它以数字开头),您还必须将名称用双引号或方括号括起来。使用 QUOTENAME 就像你之前在 proc 中所做的那样:SET @Sql = 'create view ' + QUOTENAME(@First3Digits)
  • 当您在创建视图中添加 @First3Digits 时,您也缺少撇号。您在 SELECT 块中正确执行了此操作,但在 CREATE VIEW 块中未正确执行。
  • 不要为每个参数创建一个视图,而是查看内联表值函数

标签: sql-server tsql dynamic-sql


【解决方案1】:

您的 SQL 存在许多问题。但首先调试它们的方法是打印 SQL 而不执行它,然后是正常的 SQL,您可以轻松识别它的问题。

  1. 构成视图的 SQL 周围不允许有括号。
  2. 您必须照常引用字符串,这意味着将动态字符串中的引号加倍。
  3. 按照 cmets 中的建议再次使用 quotename
  4. 无需将参数 @First3Digits 传递给 sp_executesql,因为此时您已经使用了它的值 - 如果您正在创建视图,则必须这样做。
    set @Sql = 'create view dbo.' + quotename(@First3Digits)
        + ' as'
        + ' select SubjectName'
        + ' from dbo.Subjects'
        + ' where SubjectName like ''' + @First3Digits + ''' + ''%'';';

    -- This is how you debug dynamic SQL
    print(@Sql);

    execute sp_executesql @Sql;

注意:正如我在您之前的问题中提到的,根据提供的信息,这似乎是一个非常糟糕的设计。几乎可以肯定有更好的方法来解决您的大局问题。正如 Martin Smith 所说,Inline Table Valued Function 可能值得调查。

【讨论】:

  • 不过,这是一个 SQL 注入攻击向量。如果提出观点,这可能是一个固有的问题,但仍然需要注意这一点。
  • @MarcGravell 你会如何解决它?你不能创建一个使用参数的视图......所以我猜它只是需要以某种方式转义?
  • @DaleK 我稍微修改了一下我的话;由于涉及到一个视图(第二次阅读它),那就更成问题了。我可能会用一个非常大的驳船杆来避免这种情况。类似于“社交距离”,但对于 RDBMS。
  • 是的,我在 OP 的第一个问题上添加了注释。但没有收到任何能够提出替代方案的更多详细信息。
  • 另外,您是否发现可以将足够的 SQL 放入 nvarchar(3) 以进行注入攻击? :)
猜你喜欢
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-04
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多