WHERE子句,其中一些参数可以为null

时间:2015-09-01 02:46:09

标签: sql sql-server-2012 where-clause

我的任务是在@aircraftId,@ instructorId和@reservationId对可能过滤掉的时间内拉出一些开始时间和结束时间内的记录数量(因此它在计数中忽略了它自己)。所有三个参数都是可空的,因此它们可能会或可能不会被传递,因此查询必须根据它们是否存在进行过滤。我可以使用动态Sql来做到这一点,但我更愿意避免使用它,主要是因为对于任何必须在以后处理它的人来说调试很麻烦。

在单个查询中,这是否可行(我猜它是)?或者,这是其中一种情况,我必须抓住设置,如果它们存在,用其他参数削减它?

SELECT  COUNT(*)
FROM    AVMAN.Reservation
WHERE   ( @aircraftid IS NULL
            OR ( @aircraftid IS NOT NULL
                AND AircraftId = @aircraftid
                )
        )
        OR ( @InstructorId IS NULL
                OR ( @InstructorId IS NOT NULL
                    AND InstructorUserId = @InstructorId
                )
            )
        AND ( ( -- start during the range
                StartTime >= @StartTime
                AND StartTime < @EndTime
                )
                OR ( -- end during the range 
                    EndTime > @StartTime
                    AND EndTime <= @EndTime
                    )
                OR ( -- start before the range and end after it
                    StartTime < @StartTime
                    AND EndTime > @EndTime
                    )
            )
        AND ( @ReservationId IS NULL
                OR ( ReservationId IS NOT NULL
                    AND ReservationId = @ReservationId
                    )
            )

2 个答案:

答案 0 :(得分:1)

首先,在您的原始SQL中,您有一个OR而不是AND,它会抛弃您的结果。

要整理aircraftId,instructorId和reservationId上的过滤器,您可以执行以下操作:

SELECT  COUNT(*)
FROM    AVMAN.Reservation
WHERE   
    ISNULL( @AircraftId, AircraftId ) = AircraftId 
    AND
    ISNULL( @InstructorId, InstructorId ) = InstructorId 
    AND
    ISNULL( @ReservationId, ReservationId ) = ReservationId 
    AND 
    ( ( -- start during the range
            StartTime >= @StartTime
            AND StartTime < @EndTime
            )
            OR ( -- end during the range 
                EndTime > @StartTime
                AND EndTime <= @EndTime
                )
            OR ( -- start before the range and end after it
                StartTime < @StartTime
                AND EndTime > @EndTime
                )
        )

当@AircraftId为空时,ISNULL基本上将AircraftId与@AircraftId进行比较,并将其与AircraftId(显然总是相同)进行比较。

答案 1 :(得分:0)

我不确定但是尝试在WHERE子句中使用CASE,就像这样

SELECT  COUNT(*)
FROM    AVMAN.Reservation
WHERE CASE
        WHEN @aircraftid IS NULL THEN 1 
        WHEN @aircraftid IS NOT NULL AND  AircraftId = @aircraftid THEN 1 
     END = 1 
     AND 
     CASE 
        WHEN @InstructorId IS NULL  THEN 1
        WHEN @InstructorId IS NOT NULL AND InstructorUserId = @InstructorId THEN 1
     END = 1
     AND ( ( -- start during the range
                StartTime >= @StartTime
                AND StartTime < @EndTime
                )
                OR ( -- end during the range 
                    EndTime > @StartTime
                    AND EndTime <= @EndTime
                    )
                OR ( -- start before the range and end after it
                    StartTime < @StartTime
                    AND EndTime > @EndTime
                    )
            )
        AND 
         CASE 
            WHEN @ReservationId IS NULL THEN 1
            WHEN ReservationId IS NOT NULL AND ReservationId = @ReservationId THEN 1
         END = 1