处理跨越日期范围的日期范围

时间:2019-06-17 06:44:37

标签: sql sql-server tsql

我有一张表,该表的Date Range和DateTo字段之间指定了Date Range和TotalValue字段。

取决于指定的日期范围,即:

DECLARE @ReportStartDate datetime = '31 May 2019'
DECLARE @ReportEndDate datetime = '2 Jun 2019'

它将获取NULL值以及2019-05-31-2019-06-07行,但TotalValue将为(48/7)* 2,因为它仅是范围的2天。 / p>

预期结果。

enter image description here

如果指定了以下内容:

DECLARE @ReportStartDate datetime = '04 Jun 2019'
DECLARE @ReportEndDate datetime = '14 Jun 2019'

它将获取NULL值以及2019-05-31-2019-06-05行,但TotalValue将为(48/7)* 3,因为它仅是范围的3天。 / p>

预期结果

enter image description here

有人知道如何解决这个问题吗?到目前为止,我有以下查询可以解决用例1,但是我不确定如何处理用例2

select 
    *,
    CASE WHEN DateFrom is null Then TotalValue Else (TotalValue/7) * DateDiff(dd,DateFrom,@ReportEndDate) END as CalculatedValue
from 
    #TestData
where DateFrom is null
or DateFrom >=@ReportStartDate

样本数据

CREATE TABLE #TestData
(
    DateFrom date NULL,
    DateTo date NULL,
    TotalValue money
)
INSERT INTO #TestData
(
    DateFrom,
    DateTo,
    TotalValue
)
SELECT
    NULL,
    NULL,
    250
UNION ALL
SELECT
    '2019-05-31',
    '2019-06-07',
    48
UNION ALL
SELECT
    '2019-05-24',
    '2019-05-31',
    336
UNION ALL
SELECT
    NULL,
    NULL,
    134 
UNION ALL
SELECT
    '2019-04-19',
    '2019-04-26',
    336

select * from #TestData

drop table #TestData

1 个答案:

答案 0 :(得分:1)

使用case表达式datediff和几个iif来获得CalculatedValue

case表达式有两个分支:

  1. 如果DateFromDateTo列中的任何一个都具有null而不是value,则只需返回TotalValue

  2. 这是很有趣的地方:如果日期范围重叠,请计算它们重叠的天数,然后将TotalValue除以7,再乘以天数。

我已经在代码中添加了一些注释,希望它足够清楚:

DECLARE @ReportStartDate date = '2019-05-31', @ReportEndDate date = '2019-06-02'

SELECT  DateFrom, 
        DateTo, 
        TotalValue,
        CASE 
            -- dates are null
            WHEN DateFrom IS NULL OR DateTo IS NULL THEN TotalValue

            -- devide by 7 and multiply be the number of days within range
            ELSE TotalValue / 7 * DATEDIFF(DAY,
                                           -- latest of start dates
                                           IIF(DateFrom > @ReportStartDate, DateFrom, @ReportStartDate),
                                           -- earliest of end dates
                                           IIF(DateTo < @ReportEndDate, DateTo, @ReportEndDate)
                                           )
        END  As CalculatedValue
FROM #TestData
-- Get only date ranges that overlap or the date columns are null
WHERE (DateFrom IS NULL OR DateFrom < @ReportEndDate)
AND (DateTo IS NULL OR DateTo > @ReportStartDate)