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

WHERE clause where some parameters can be null

我的任务是提取开始时间和结束时间内的记录数,同时 可能 被@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
                    )
            )

我不确定,但尝试像这样在 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

首先,在您原来的 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
                )
        )

ISNULL 基本上是在 AircraftId 不为空时将 AircraftId 与 @AircraftId 进行比较,而在 @AircraftId 为空时则与 AircraftId(显然始终相同)进行比较。