【问题标题】:Execute dynamic query with IF-ELSE statements and sp_executesql command使用 IF-ELSE 语句和 sp_executesql 命令执行动态查询
【发布时间】:2021-01-02 16:48:16
【问题描述】:

我使用 SQL Server 创建了下表

CREATE TABLE test 
(
     id_number NVARCHAR(50) NOT NULL,
     number_of_products NVARCHAR(50) NOT NULL
);

INSERT INTO test (id_number, number_of_products)
VALUES (1000077004, 3),
       (1000077005, 4),
       (1000077006, 4),
       (1000077007, 5),
       (1000077008, 5),
       (1000077009, 6);

我还创建了一个自定义过程,使用动态 SQL 来运行面向自定义的查询

程序:

CREATE PROCEDURE [dbo].[usp_dynamicquery1]
    (@TableName NVARCHAR(50) = NULL,
     @Field     NVARCHAR(100) = NULL,
     @Criterion NVARCHAR(100) = NULL,
     @Parameter NVARCHAR(100) = NULL)
AS          
BEGIN
    SET NOCOUNT ON;  
 
    DECLARE @SQL          NVARCHAR(MAX)
    DECLARE @ParameterDef NVARCHAR(500)
    DECLARE @all          VARCHAR(2) = '-1'

    SET @ParameterDef = '@TableName NVARCHAR(50),
                         @Field     NVARCHAR(100),
                         @Criterion NVARCHAR(100),
                         @Parameter  NVARCHAR(100)'

    SET @SQL = 'SELECT *
                FROM TableName
                WHERE Field Criterion Parameter'

    SET @TableName = CASE 
                        WHEN @TableName IS NOT NULL AND @TableName <> 0
                           THEN SET @SQL = @SQL+ ' AND TableName = @TableName'
                           ELSE  '''' + @all + ''' = ''' + @all + ''''
                     END

    SET @Field = CASE 
                    WHEN @Field IS NOT NULL AND @Field <> 0
                       THEN SET @SQL = @SQL+ ' AND Field = @Field'
                       ELSE  '''' + @all + ''' = ''' + @all + ''''
                 END

    SET @Criterion = CASE 
                        WHEN @Criterion = 'greater than'
                           THEN SET @SQL = @SQL+ ' AND Criterion = >'
                        WHEN @Criterion = 'greater than or equal'
                           THEN SET @SQL = @SQL+ ' AND Criterion = >='
                        WHEN @Criterion = 'less than'
                           THEN SET @SQL = @SQL+ ' AND Criterion = <'
                        WHEN @Criterion = 'less than or equal'
                           THEN SET @SQL = @SQL+ ' AND Criterion = <='
                        WHEN @Criterion = 'equal'
                           THEN SET @SQL = @SQL+ ' AND Criterion = ='
                        WHEN @Criterion = 'not equal'
                           THEN SET @SQL = @SQL+ ' AND Criterion = <>'
                        ELSE  '''' + @all + ''' = ''' + @all + ''''
                     END

    SET @Parameter = CASE 
                        WHEN @Parameter IS NOT NULL AND @Parameter <> 0
                           THEN SET @SQL = @SQL+ ' AND Parameter = @Parameter'
                           ELSE  '''' + @all + ''' = ''' + @all + ''''
                     END

    EXEC sp_executesql @SQL,  
              @ParameterDef, 
              @TableName = @TableName, @Field = @Field, @Criterion = @Criterion, @Parameter = @Parameter
END

简而言之,我将解释我的程序的作用:

  • 第 1 步:将 4 个参数作为输入 (TableName, Field, Criterion, Parameter)

  • 第 2 步:设置查询以根据样本条件(大于、小于等)选择所有值

  • 第 3 步:运行 4 个 if-else 语句来定义每个变量的值。基本上,如果用户给出一个值,则参数采用该值,否则参数采用值 '-1' (@all)

  • 第 4 步:我执行命令 EXEC sp_executesql 以动态完成我的查询

当我尝试创建程序时,出现以下错误:

消息 156,级别 15,状态 1,过程 usp_dynamicquery1,第 45 行 [批处理开始第 0 行]
关键字“SET”附近的语法不正确。

消息 156,级别 15,状态 1,过程 usp_dynamicquery1,第 46 行 [批处理开始行 0]
关键字“ELSE”附近的语法不正确。

消息 156,级别 15,状态 1,过程 usp_dynamicquery1,第 51 行 [批处理开始行 0]
关键字“SET”附近的语法不正确。

运行以下查询时的预期结果:

[usp_dynamicquery1] @TableName='test', @Field='number_of_products', @Criterion='greater than', @Parameter = '4'

返回 number_of_products > 4 的 id_numbers(因此是测试表的最后三行)。

【问题讨论】:

  • case 是一个 表达式 而不是语句,因此只能返回一个值,不能运行语句。您需要将它们全部重写以返回值。
  • @DaleK 感谢您的评论。由于我是 SQL 的新用户,您能否提供一个示例,根据我的 CASE WHEN 场景突出显示您的解决方案?了解正确的语法会很有帮助。谢谢。
  • 请咨询Official Documentation我不太了解你的逻辑,无法为你重写。
  • 在你的 SET \@SQL 语句中你没有包含参数的值,你应该有一些类似的东西 SET \@sql = N'SELECT * FROM ' + @table;跨度>

标签: sql-server stored-procedures dynamic-sql sp-executesql


【解决方案1】:

你有正确的想法,并且朝着正确的方向前进。我想我会帮助你了解我将如何处理这个问题。

这是我的存储过程版本:

CREATE OR ALTER PROCEDURE [dbo].[usp_dynamicquery1] (
    @TableName NVARCHAR(50),
    @Field NVARCHAR(100) = NULL,
    @Criterion NVARCHAR(100) = NULL,
    @Parameter NVARCHAR(100) = NULL,
    @All VARCHAR(2) = '-1'
)
AS          
BEGIN

    SET NOCOUNT ON;  
 
    DECLARE 
        @SQL NVARCHAR(MAX),
        @SQL_WHERE NVARCHAR(MAX),
        @ParameterDef NVARCHAR(500);

    SET @ParameterDef = '@Parameter NVARCHAR(100)'
    SET @SQL = 'SELECT * FROM ' + @TableName;
    SET @SQL_WHERE = '';

    /* BUILD THE WHERE CLAUSE IF @Field IS PRESENT */

    IF NULLIF ( @Field, '' ) IS NOT NULL BEGIN

        -- Field.
        SET @SQL_WHERE = ' WHERE ' + @Field;

        -- Field Comparison.
        SET @SQL_WHERE += CASE @Criterion 
            WHEN 'greater than' THEN ' >'
            WHEN 'greater than or equal' THEN ' >='
            WHEN 'less than' THEN ' <'
            WHEN 'less than or equal' THEN ' <='
            WHEN 'not equal' THEN ' <>'
            ELSE ' ='
        END;

        -- Field Parameter.
        SET @SQL_WHERE += ' @Parameter';

        -- Set @Parameter value.
        SET @Parameter =
            CASE WHEN NULLIF ( @Parameter, '' ) IS NOT NULL
                THEN @Parameter
                ELSE @All
            END;

    END

    -- Finish SQL statement.
    SET @SQL = @SQL + ISNULL ( @SQL_WHERE, '' ) + ';';

    -- Execute the dynamic statement.
    EXEC sp_executesql @SQL, @ParameterDef, @Parameter = @Parameter;

END
GO

一些值得注意的快速事项:

  • @TableName必须为必填项,否则,你打算查询什么?

  • WHERE 子句仅在存在@Field 时才会构造。

  • 缩短了 @ParameterDef 变量以仅包含 @Parameter。 t-sql 的其余部分在调用sp_execute_sql 之前形成。我留下了@Parameter,这样您就不必担心值周围的单个刻度等。

  • 将 @All 作为 DEFAULTed 参数 (-1) 添加到 SP 中,如果需要,可以更改该值。

【讨论】:

  • 感谢您的回答。实际上,它按预期工作。总结一下您的方法,您基本上创建一个空的 SQL_WHERE,然后基于@Field、@Criterion 和@Parameter 构造语句。您还提到 @TableName 是必需的。你在哪里定义这个?也许在sql语句中SET @SQL = 'SELECT * FROM ' + @TableName;?
  • @NikSp 我只是将您的 SP 签名从 @TableName NVARCHAR(50) = NULL, ... 更改为 @TableName NVARCHAR(50), ...。通过删除 NULL 的 DEFAULT,任何调用 SP 的东西都必须为 @TableName 提供一个值。
猜你喜欢
  • 2011-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-14
相关资源
最近更新 更多