首页 > 解决方案 > 动态 SQL 遇到的问题

问题描述

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 行
关键字“视图”附近的语法不正确

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

标签: sql-servertsqldynamic-sql

解决方案


您的 SQL 存在许多问题。但首先调试它们的方法是打印 SQL 而不执行它,然后是正常的 SQL,你可以很容易地识别它有什么问题。

  1. 构成视图的 SQL 周围不允许有括号。
  2. 您必须照常引用您的字符串,这意味着将动态字符串中的引号加倍。
  3. 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 所评论的,内联表值函数可能值得研究。


推荐阅读