MS SQL:选择许多日期列包含范围的行,如果不为空

时间:2016-06-03 10:03:00

标签: sql-server sql-server-2008

我认为这是一个相当复杂的查询,但尚未达成解决方案,我想知道是否可以通过复杂的查询来完成它,或者我需要对结果进行后期处理。

我有预算表,有预算代码,还有几个日期,比如enterDate,deliveryDate,desiredDeliveryDate,shippingDate等。

有些日期可能为空。其他人可能会被设定。

我需要一个查询来返回那些任何日期都在日期范围间隔内的预算行。但我不想考虑空值的日期。更具体地说,我试着举个例子。

BudgetID  |  D1  |  D2  |  D3  |  D5  | 
a         | NULL | NULL | NULL | NULL |
b         | NULL |  IR  |  OR  |  OR  |
c         | NULL | NULL | NULL |  IR  |
d         |  OR  | NULL | NULL | NULL |

NULL当然意味着值为null。 IR表示日期为IN RANGE。 或者说日期是OUT RANGE。

结果应如下:

BudgetID  |  D1  |  D2  |  D3  |  D5  | 
b         | NULL |  IR  |  OR  |  OR  |
c         | NULL | NULL | NULL |  IR  |

预算a不匹配,因为所有日期列都为NULL。 预算b确实匹配,因为范围内至少有一个NOT NULL日期。 由于与avobe相同的原因,预算c确实交配。 预算d不匹配,因为所有NOT NULL日期都在范围之外。

提前致谢。

编辑:

考虑到查询创建的性质,我想到了一个可能的解决方案。由于我事先知道了范围并且我使用C#中的string.Format参数化地构造了查询,因此在与范围进行比较之前,我决定使用ISNULL,其中每个DATE列的范围之外的日期值。这将使NULL日期始终失败。

3 个答案:

答案 0 :(得分:1)

试试这个:

SELECT BudgetId, D1, D2, D4, D4, D5
FROM YourTable
WHERE  ISNULL(D1, DATEADD(DD, 1, @max)) BETWEEN @min AND @max
    OR ISNULL(D2, DATEADD(DD, 1, @max)) BETWEEN @min AND @max
    OR ISNULL(D3, DATEADD(DD, 1, @max)) BETWEEN @min AND @max
    OR ISNULL(D4, DATEADD(DD, 1, @max)) BETWEEN @min AND @max
    OR ISNULL(D5, DATEADD(DD, 1, @max)) BETWEEN @min AND @max

答案 1 :(得分:0)

根据这四个DT列中NULL的分布和/或这些条件的选择性,我将使用以下一个下面的查询:

SELECT  b.BudgetID 
FROM    dbo.Budget b
WHERE   b.D1 BETWEEN @a AND @b
OR      b.D2 BETWEEN @a AND @b
OR      b.D3 BETWEEN @a AND @b
OR      b.D4 BETWEEN @a AND @b

- 或

SELECT  DISTINCT b.BudgetID 
FROM    dbo.Budget b
CROSS APPLY (
        SELECT D1 WHERE D1 IS NOT NULL
        UNION ALL 
        SELECT D2 WHERE D2 IS NOT NULL
        UNION ALL 
        SELECT D3 WHERE D3 IS NOT NULL
        UNION ALL 
        SELECT D4 WHERE D4 IS NOT NULL
) ca (AllDt)
WHERE ca.AllDt BETWEEN @a AND @b

- 或

SELECT  b.BudgetID 
FROM    dbo.Budget b
WHERE   b.D1 BETWEEN @a AND @b
UNION -- UNION removes duplicated values
SELECT  b.BudgetID 
FROM    dbo.Budget b
WHERE   b.D2 BETWEEN @a AND @b
UNION 
SELECT  b.BudgetID 
FROM    dbo.Budget b
WHERE   b.D3 BETWEEN @a AND @b
UNION 
SELECT  b.BudgetID 
FROM    dbo.Budget b
WHERE   b.D4 BETWEEN @a AND @b

答案 2 :(得分:0)

这可能对你的情况有用..

CREATE TABLE #temp   (BudgetID  VARCHAR(3),  D1 DATETIME ,  D2 DATETIME ,  D3 DATETIME ,  D5 DATETIME ) 
INSERT #temp (BudgetID  ,  D1  ,  D2  ,  D3  ,  D5  ) 
VALUES
('a' , NULL , NULL , NULL , NULL ),
('b' , NULL , 'Apr 01 2016 12:00:00:000AM',  'May 30 2016 12:00:00:000AM', 'Jun 10 2016 12:00:00:000AM' ),
('c' , NULL , NULL , NULL , 'Apr 15 2016 12:00:00:000AM' ),
('d' ,  'Jan 30 2016 12:00:00:000AM', NULL , NULL , NULL )
/*INSERT #temp (BudgetID  ,  D1  ,  D2  ,  D3  ,  D5  ) 
VALUES('e' , 'Apr 30 2016 12:00:00:000AM' , 'Apr 10 2016 12:00:00:000AM' , NULL , NULL )*/
SELECT BudgetID,D1 as DATE FROM (
select BudgetID,D1 from #temp
UNION
select BudgetID,D2 from #temp
UNION
select BudgetID,D3 from #temp
UNION 
select BudgetID,D5 from #temp
)a WHERE a.D1 between '2016-04-01' AND '2016-04-30' 
--(OR)
SELECT BudgetID,ColumnName,DATES
FROM
(
SELECT ROW_NUMBER () OVER(ORDER BY (BudgetID) ) Row_NO,BudgetID , D1  ,  D2  ,  D3  ,  D5    
FROM #TEMP
) AS a
UNPIVOT
(DATES FOR ColumnName IN ( D1  ,  D2  ,  D3  ,  D5  )) AS up
WHERE DATES between '2016-04-01' AND '2016-04-30' 

但是需要再看一个场景......如果同一行有多个日期且日期在给定范围内,那么它将返回多行(要查看此场景,只需取消注释并insert budjetID&# 39; e'进入临时表)。 如果您的要求只是找到budgetID,那么只需选择distinct budgetID