SQL Server查询将花费的时间分成各自的“月”和“#34;柱

时间:2014-08-04 12:58:22

标签: sql sql-server date split

我使用的是SQL Server 2012,我需要编写一个查询来分割到达日期和出发日期之间的差异(即花费的夜晚数量),并将结果发布到各自的{ {1}}栏。

我已经知道如何编写将获取我的到达日期和离开日期的查询,但这是我最难解决的部分。我的最终结果需要看起来像这样:

Month

ID Name Date of Arrival Date of Departure Jan Feb Mar Apr 203 Mr Smith 2014.02.24 2014.03.02 5 1 455 Mr Jones 2014.04.10 2014.04.17 7 IDNameDate of Arrival来自特定的表格。如何将拆分部分添加到现有查询中,以便输出如上所示?

在做了一些研究之后,我发现Date of Departure表可能会有所帮助,但我不知道如何在我的查询中实现这一点。

感谢您的投入。

2 个答案:

答案 0 :(得分:2)

我认为Calendar表将是最佳选择。我认为查询看起来像这样,我将你的表命名为VisitDate,并假设Calendar表有一个Date字段和一个Month字段。

select ID, Name, [DATEADD of Arrival], [DATEADD of Departure], 
    sum(case when c.month = 1 then 1 else 0 end) as Jan, 
    sum(case when c.month = 2 then 1 else 0 end) as Feb, 
    sum(case when c.month = 3 then 1 else 0 end) as Mar, 
    sum(case when c.month = 4 then 1 else 0 end) as Apr 
from 
    VisitDate
    join Calendar c on c.Date >= [DATEADD of Arrival] and c.Date <= [DATEADD of Departure]

答案 1 :(得分:0)

这也可以通过一组case语句来完成: 让我们做一些测试数据:

DECLARE @Booking TABLE
(
    GuestID INT,
    Name VARCHAR(50),
    ArrivalDate DATETIME,
    DepartureDate DATETIME
)

INSERT INTO @Booking
( GuestID, Name, ArrivalDate, DepartureDate )
VALUES
( 203, 'Mr Smith', '02-24-2014', '03-02-2014' ),
( 455, 'Mr Jones', '04-10-2014', '04-17-2014' ),
( 531, 'Mrs James', '07-10-2014', '09-17-2014' );

今年要制作日历CTE:

DECLARE @CheckYear INT = 2014

;WITH MonthInfo AS
(
    SELECT
    DATEADD(DAY, 0, DATEADD(MONTH, 0, DATEADD(YEAR, @CheckYear - 1900, 0))) JanStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 1, DATEADD(YEAR, @CheckYear - 1900, 0))) FebStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 2, DATEADD(YEAR, @CheckYear - 1900, 0))) MarStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 3, DATEADD(YEAR, @CheckYear - 1900, 0))) AprStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 4, DATEADD(YEAR, @CheckYear - 1900, 0))) MayStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 5, DATEADD(YEAR, @CheckYear - 1900, 0))) JunStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 6, DATEADD(YEAR, @CheckYear - 1900, 0))) JulStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 7, DATEADD(YEAR, @CheckYear - 1900, 0))) AugStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 8, DATEADD(YEAR, @CheckYear - 1900, 0))) SepStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 9, DATEADD(YEAR, @CheckYear - 1900, 0))) OctStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 10, DATEADD(YEAR, @CheckYear - 1900, 0))) NovStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 11, DATEADD(YEAR, @CheckYear - 1900, 0))) DecStart,
    DATEADD(DAY, 0, DATEADD(MONTH, 12, DATEADD(YEAR, @CheckYear - 1899, 0))) EOY
)

现在我们运行查询并根据日历检查它,并提取所有重叠日期并获取天数

SELECT b.*,
    CASE WHEN b.ArrivalDate > m.JanStart AND b.ArrivalDate < m.FebStart THEN
        (CASE WHEN b.DepartureDate < m.FebStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.FebStart)
        END)
        WHEN b.ArrivalDate < m.JanStart AND b.DepartureDate > m.JanStart AND b.DepartureDate < m.FebStart THEN
            DATEDIFF(DAY, m.JanStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.JanStart AND b.DepartureDate > m.JanStart AND b.DepartureDate > m.FebStart THEN
            DATEDIFF(DAY, m.JanStart, m.FebStart)

    ELSE 0
    END JanDays,
    CASE WHEN b.ArrivalDate > m.FebStart AND b.ArrivalDate < m.MarStart THEN
        (CASE WHEN b.DepartureDate < m.MarStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.MarStart)
        END)
        WHEN b.ArrivalDate < m.FebStart AND b.DepartureDate > m.FebStart AND b.DepartureDate < m.MarStart THEN
            DATEDIFF(DAY, m.FebStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.FebStart AND b.DepartureDate > m.FebStart AND b.DepartureDate > m.MarStart THEN
            DATEDIFF(DAY, m.FebStart, m.MarStart)

    ELSE 0
    END FebDays,
    CASE WHEN b.ArrivalDate > m.MarStart AND b.ArrivalDate < m.AprStart THEN
        (CASE WHEN b.DepartureDate < m.AprStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.AprStart)
        END)
        WHEN b.ArrivalDate < m.MarStart AND b.DepartureDate > m.MarStart AND b.DepartureDate < m.AprStart THEN
            DATEDIFF(DAY, m.MarStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.MarStart AND b.DepartureDate > m.MarStart AND b.DepartureDate > m.AprStart THEN
            DATEDIFF(DAY, m.MarStart, m.AprStart)
    ELSE 0
    END MarDays,
    CASE WHEN b.ArrivalDate > m.AprStart AND b.ArrivalDate < m.MayStart THEN
        (CASE WHEN b.DepartureDate < m.MayStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.MarStart)
        END)
        WHEN b.ArrivalDate < m.AprStart AND b.DepartureDate > m.AprStart AND b.DepartureDate < m.MayStart THEN
            DATEDIFF(DAY, m.AprStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.AprStart AND b.DepartureDate > m.AprStart AND b.DepartureDate > m.MayStart THEN
            DATEDIFF(DAY, m.AprStart, m.MayStart)

    ELSE 0
    END AprDays,
    CASE WHEN b.ArrivalDate > m.MayStart AND b.ArrivalDate < m.JunStart THEN
        (CASE WHEN b.DepartureDate < m.JunStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.JunStart)
        END)
        WHEN b.ArrivalDate < m.MayStart AND b.DepartureDate > m.MayStart AND b.DepartureDate < m.JunStart THEN
            DATEDIFF(DAY, m.MayStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.MayStart AND b.DepartureDate > m.MayStart AND b.DepartureDate > m.JunStart THEN
            DATEDIFF(DAY, m.MayStart, m.JunStart)
    ELSE 0
    END MayDays,
    CASE WHEN b.ArrivalDate > m.JunStart AND b.ArrivalDate < m.JulStart THEN
        (CASE WHEN b.DepartureDate < m.JulStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.JulStart)
        END)
        WHEN b.ArrivalDate < m.JunStart AND b.DepartureDate > m.JunStart AND b.DepartureDate < m.JulStart THEN
            DATEDIFF(DAY, m.JunStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.JunStart AND b.DepartureDate > m.JunStart AND b.DepartureDate > m.JulStart THEN
            DATEDIFF(DAY, m.JunStart, m.JulStart)
    ELSE 0
    END JunDays,
    CASE WHEN b.ArrivalDate > m.JulStart AND b.ArrivalDate < m.AugStart THEN
        (CASE WHEN b.DepartureDate < m.AugStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.AugStart)
        END)
        WHEN b.ArrivalDate < m.JulStart AND b.DepartureDate > m.JulStart AND b.DepartureDate < m.AugStart THEN
            DATEDIFF(DAY, m.JulStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.JulStart AND b.DepartureDate > m.JulStart AND b.DepartureDate > m.AugStart THEN
            DATEDIFF(DAY, m.JulStart, m.AugStart)
    ELSE 0
    END JulDays,
    CASE WHEN b.ArrivalDate > m.AugStart AND b.ArrivalDate < m.SepStart THEN
        (CASE WHEN b.DepartureDate < m.SepStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.SepStart)
        END)
        WHEN b.ArrivalDate < m.AugStart AND b.DepartureDate > m.AugStart AND b.DepartureDate < m.SepStart THEN
            DATEDIFF(DAY, m.AugStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.AugStart AND b.DepartureDate > m.AugStart AND b.DepartureDate > m.SepStart THEN
            DATEDIFF(DAY, m.AugStart, m.SepStart)
    ELSE 0
    END AugDays,
    CASE WHEN b.ArrivalDate > m.SepStart AND b.ArrivalDate < m.OctStart THEN
        (CASE WHEN b.DepartureDate < m.OctStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.OctStart)
        END)
        WHEN b.ArrivalDate < m.SepStart AND b.DepartureDate > m.SepStart AND b.DepartureDate < m.OctStart THEN
            DATEDIFF(DAY, m.SepStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.SepStart AND b.DepartureDate > m.SepStart AND b.DepartureDate > m.OctStart THEN
            DATEDIFF(DAY, m.SepStart, m.OctStart)
    ELSE 0
    END SepDays,
    CASE WHEN b.ArrivalDate > m.OctStart AND b.ArrivalDate < m.NovStart THEN
        (CASE WHEN b.DepartureDate < m.NovStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.NovStart)
        END)
        WHEN b.ArrivalDate < m.OctStart AND b.DepartureDate > m.OctStart AND b.DepartureDate < m.NovStart THEN
            DATEDIFF(DAY, m.OctStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.OctStart AND b.DepartureDate > m.OctStart AND b.DepartureDate > m.NovStart THEN
            DATEDIFF(DAY, m.OctStart, m.NovStart)
    ELSE 0
    END OctDays,
    CASE WHEN b.ArrivalDate > m.NovStart AND b.ArrivalDate < m.DecStart THEN
        (CASE WHEN b.DepartureDate < m.DecStart THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.DecStart)
        END)
        WHEN b.ArrivalDate < m.NovStart AND b.DepartureDate > m.NovStart AND b.DepartureDate < m.DecStart THEN
            DATEDIFF(DAY, m.NovStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.NovStart AND b.DepartureDate > m.NovStart AND b.DepartureDate > m.DecStart THEN
            DATEDIFF(DAY, m.NovStart, m.DecStart)
    ELSE 0
    END NovDays,
    CASE WHEN b.ArrivalDate > m.DecStart AND b.ArrivalDate < m.EOY THEN
        (CASE WHEN b.DepartureDate < m.EOY THEN DATEDIFF(DAY, b.ArrivalDate, b.DepartureDate) 
            ELSE DATEDIFF(DAY, b.ArrivalDate, m.EOY)
        END)
        WHEN b.ArrivalDate < m.DecStart AND b.DepartureDate > m.DecStart AND b.DepartureDate < m.EOY THEN
            DATEDIFF(DAY, m.DecStart, b.DepartureDate) + 1
        WHEN b.ArrivalDate < m.DecStart AND b.DepartureDate > m.DecStart AND b.DepartureDate > m.EOY THEN
            DATEDIFF(DAY, m.DecStart, m.EOY)
    ELSE 0
    END DecDays
FROM @Booking b
INNER JOIN MonthInfo m
    ON b.ArrivalDate >= m.JanStart AND b.ArrivalDate < m.EOY

这是输出:

GuestID Name    ArrivalDate DepartureDate   JanDays FebDays MarDays AprDays MayDays JunDays JulDays AugDays SepDays OctDays NovDays DecDays
203 Mr Smith    2014-02-24 00:00:00.000 2014-03-02 00:00:00.000 0   5   2   0   0   0   0   0   0   0   0   0
455 Mr Jones    2014-04-10 00:00:00.000 2014-04-17 00:00:00.000 0   0   0   7   0   0   0   0   0   0   0   0
531 Mrs James   2014-07-10 00:00:00.000 2014-09-17 00:00:00.000 0   0   0   0   0   0   22  31  17  0   0   0

根据数据,我让詹姆斯太太在七月到达,住了几个月,然后在九月离开,所以你可以看到几个月的日子重叠。 case语句可以转换为在报告年度中传递的函数,以使代码更简单,但我只想展示代码的工作方式。

另一种方法是制作一个数字表,并创建与通过日期相对应的一年中的每一天:

DECLARE @StartDate DATETIME
SELECT @StartDate = MIN(ArrivalDate) - 1 FROM @Booking

DECLARE @number_of_numbers INT = 100000

;WITH
a AS (SELECT 1 AS i UNION ALL SELECT 1),
b AS (SELECT 1 AS i FROM a AS x, a AS y),
c AS (SELECT 1 AS i FROM b AS x, b AS y),
d AS (SELECT 1 AS i FROM c AS x, c AS y),
e AS (SELECT 1 AS i FROM d AS x, d AS y),
f AS (SELECT 1 AS i FROM e AS x, e AS y),
numbers AS 
(
    SELECT TOP(@number_of_numbers)
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS number
    FROM f
), 

CalTable AS
(
    SELECT DATEADD(DAY, n.number, @StartDate) CheckDate
    FROM numbers n
)

然后只讨论几个月:

SELECT b.GuestID,
    b.Name,
    SUM(CASE WHEN MONTH(c.CheckDate) = 1 THEN 1 ELSE 0 END) JanDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 2 THEN 1 ELSE 0 END) FebDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 3 THEN 1 ELSE 0 END) MarDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 4 THEN 1 ELSE 0 END) AprDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 5 THEN 1 ELSE 0 END) MayDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 6 THEN 1 ELSE 0 END) JunDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 7 THEN 1 ELSE 0 END) JulDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 8 THEN 1 ELSE 0 END) AugDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 9 THEN 1 ELSE 0 END) SepDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 10 THEN 1 ELSE 0 END) OctDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 11 THEN 1 ELSE 0 END) NovDays,
    SUM(CASE WHEN MONTH(c.CheckDate) = 12 THEN 1 ELSE 0 END) DecDays
FROM CalTable c
INNER JOIN @Booking b
    ON c.CheckDate BETWEEN b.ArrivalDate AND b.DepartureDate
GROUP BY b.GuestID, b.Name

这是输出:

GuestID Name    JanDays FebDays MarDays AprDays MayDays JunDays JulDays AugDays SepDays OctDays NovDays DecDays
455 Mr Jones    0   0   0   8   0   0   0   0   0   0   0   0
203 Mr Smith    0   5   2   0   0   0   0   0   0   0   0   0
531 Mrs James   0   0   0   0   0   0   22  31  17  0   0   0