【问题标题】:Conditional where on stored procedure有条件的 where 存储过程
【发布时间】:2016-12-09 11:44:52
【问题描述】:

我在 SQL Server 上有一个存储过程,它采用 3 个参数,所有参数都是可选的。 参数为monthyearclass(仅作为示例)。

如果没有值通知month,则默认值为当前月份,对于year,默认值为当前年份。

然后在类中,如果没有通知值,则不会使用where 条件,或者至少是WHERE class IS NOT NULL(必须返回所有class)。

存储过程根据参数运行一个select。

存储过程:

CREATE PROCEDURE [dbo].[SP_TEST]
    @month INT,
    @year INT,
    @class NVARCHAR(10) = NULL
AS
BEGIN
    SET NOCOUNT ON

    IF @month IS NULL
        SET @month = MONTH(GETDATE())

    IF @year IS NULL
        SET @year = YEAR(GETDATE())

    SELECT
        *
    FROM 
        TABLE_TEST V
    WHERE
        MONTH(V.DATE) = @month AND
        YEAR(V.DATE) = @year AND
        CLASS = ???

所以,在WHERE,我尝试了以下代码:

代码 01:

WHERE
    MONTH(V.DATE) = @month AND
    YEAR(V.DATE) = @year AND
    (@class IS NOT NULL AND CLASS = @class)

结果:

  • 如果我将值传递给@class,一切正常

  • 如果我将NULL 传递给@class,则不会返回任何内容。

代码 02:

WHERE
    MONTH(V.DATE) = @month AND
    YEAR(V.DATE) = @year AND
    V.CLASS = CASE WHEN @class != NULL THEN @class END

结果:

  • 如果我将值传递给@class,则不会返回任何内容。

  • 如果我将NULL 传递给@class,则不会返回任何内容。

我如何调用存储过程:

class 上使用NULL

EXEC [dbo].[SP_TEST]
    @month = NULL,
    @year = NULL,
    @class = NULL

有一些class

EXEC [dbo].[SP_TEST]
    @month = NULL,
    @year = NULL,
    @class = 'TEST_A'

【问题讨论】:

  • 02) @class != NULL >>> @class IS NULL / @class IS NOT NULL 01) @class IS NOT NULL AND CLASS = @class - 如果@class 为 NULL(这是你的观点)那又怎样?你几乎做到了。
  • 我将 01 更新为 ((@class IS NOT NULL AND V.CLASS = @class) OR (@class IS NULL)) 并且工作了!

标签: sql-server stored-procedures sql-server-2016


【解决方案1】:

一种可能的解决方案是:

WHERE V.CLASS = ISNULL(@class, V.CLASS)

这意味着:V.CLASS = @class 或(如果 @classnullV.CLASS = V.CLASS,这总是正确的。

顺便说一句:您的查询可能不高效,因为使用MONTHYEAR 不允许使用索引。

创建您想要返回的月份的第一天和下个月的第一天:

DECLARE @monthStart DATETIME
DECLARE @monthEnd DATETIME
SET @monthStart = DATETIMEFROMPARTS
                  (
                    ISNULL(@year, YEAR(GETDATE())), 
                    ISNULL(@month, MONTH(GETDATE())), 
                    1, 
                    0,
                    0, 
                    0, 
                    0
                  )
SET @monthEnd = DATEADD(mm, 1, @monthStart)

我的建议是计算一年中请求月份的第一个日期和最后一个日期,然后使用

WHERE V.DATE >= @monthStart AND V.DATE < @monthEnd

【讨论】:

  • tks! :D 你的代码很干净,解释也很好!而且关于月份和年份的额外信息很棒!
【解决方案2】:

你的代码在 WHERE CLOUSE 之后应该是这样的

WHERE
     MONTH(V.DATE) = @month AND
     YEAR(V.DATE) = @year AND
     @class IS NULL OR V.CLASS = @class

【讨论】:

  • 虽然这也是正确的,但不鼓励使用不解释任何内容的单行答案。至少写一两行关于为什么会这样。
【解决方案3】:

你可以用这个

在哪里 MONTH(V.DATE) = @month 和 YEAR(V.DATE) = @year AND

 class = case
 when class=@class then @class
 else table_name.class

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-29
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 2015-11-21
    • 1970-01-01
    相关资源
    最近更新 更多