我一直使用 COALESCE()
生成动态 WHERE
语句,以返回传入的值或返回所有记录。
但是,当我需要检查两列时,我似乎无法做到这一点,如果没有传入参数,则返回所有记录。这是我的代码片段:
DECLARE @MaxAge INT = NULL --- Example value: 5
SELECT
*
FROM
dbo.Vehicle
WHERE
DATEPART(YEAR, RegistrationDate) <=
CASE
WHEN @MaxAge IS NOT NULL
THEN (DATEPART(YEAR,GETDATE()) - @MaxAge)
ELSE DATEPART(YEAR, RegistrationDate)
END
OR
DATEPART(YEAR, ProductionDate) <=
CASE
WHEN @MaxAge IS NOT NULL
THEN (DATEPART(YEAR,GETDATE()) - @MaxAge)
ELSE DATEPART(YEAR, ProductionDate)
END
我想做的(用简单的英语)是:
Give me all the rows in the vehicle table where the YEAR part of the RegistrationDate is less than the @MaxAge or the YEAR part of the ProductionDate is less than the @MaxAge. If @MaxAge is NULL, then give me the whole lot no matter when it was made or registered.
有时,如果车辆尚未注册,表中的 RegistrationDate
值将为 NULL。有时,如果卖家根本不知道生产日期,ProductionDate
可以为 NULL。
解决这个问题的最佳方法是什么?我试过在 SQL 书籍和网上查找,但找不到任何符合这种情况的内容。
最佳答案
你可以稍微简化一下:
SELECT *
FROM dbo.Vehicle
WHERE @MaxAge IS NULL -- return everything if null
OR DATEDIFF(YEAR, RegistrationDate, GETDATE()) <= @MaxAge
OR DATEDIFF(YEAR, ProductionDate, GETDATE()) <= @MaxAge
请注意,如果 @MaxAge
为空,OR ... <= @MaxAge
语句将返回 false。您仍然会得到 WHERE @MaxAge IS NULL
中的所有内容.
我在这里假设 @MaxAge
代表您关心的最旧的注册。如果 MaxAge 为 5,您将返回 '01/01/2011'
或之后的所有结果.
编辑:
根据 ErikE 的评论,请注意 DATEDIFF()
有一些您可能意想不到的古怪行为。
考虑这两个语句是等价的:
SELECT DATEDIFF(YEAR, '01/01/2011', GETDATE()) -- = 5
SELECT DATEDIFF(YEAR, '12/31/2011', GETDATE()) -- = 5
要解决此问题,您可以尝试:
SELECT *
FROM dbo.Vehicle
WHERE @MaxAge IS NULL -- return everything if null
OR DATEADD(YEAR, -@MaxAge, GETDATE()) <= RegistrationDate
OR DATEADD(YEAR, -@MaxAge, GETDATE()) <= ProductionDate
这将返回 @MaxAge
从今天(包括当前时间)开始的几年,并返回之后发生的一切。在这种情况下,5 年零 10 秒前发生的任何事情都会被排除在外。要解决此问题,您可以使用:
DECLARE @TodayNoTime datetime = DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0) -- 05/25/2016 00:00:00.000
SELECT *
FROM dbo.Vehicle
WHERE @MaxAge IS NULL -- return everything if null
OR DATEADD(YEAR, -@MaxAge, @TodayNoTime) <= RegistrationDate -- note the negative sign
OR DATEADD(YEAR, -@MaxAge, @TodayNoTime) <= ProductionDate
这将返回 @MaxAge
之前发生的任何事情多年前的今天,无论何时。
最后,使用 COALESCE()
在这种情况下将不起作用,因为您只会比较一列或另一列,以先发现非空者为准。所以如果RegistrationDate
超出您的参数范围,但 ProductionDate
掉进去,你就会错过这个记录。因此,我已从答案中删除该声明。
关于sql - 如何使用具有 OR 子句的 COALESCE 创建动态 WHERE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37446864/