Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server查询将花费的夜数拆分为相应的“月”列_Sql_Sql Server_Date_Split - Fatal编程技术网

SQL Server查询将花费的夜数拆分为相应的“月”列

SQL Server查询将花费的夜数拆分为相应的“月”列,sql,sql-server,date,split,Sql,Sql Server,Date,Split,我使用的是SQL Server 2012,我需要编写一个查询,将到达日期和离开日期之间的差异(即花费的夜数)拆分,并将结果发布到相应的月份列中 我已经知道如何编写查询来获取我的到达日期和离开日期,但对我来说最困难的部分是分割部分。我的最终结果需要如下所示: ID Name Date of Arrival Date of Departure Jan Feb Mar Apr 203 Mr Smith 2014.02.24 2014.03.02

我使用的是SQL Server 2012,我需要编写一个查询,将到达日期和离开日期之间的差异(即花费的夜数)拆分,并将结果发布到相应的月份列中

我已经知道如何编写查询来获取我的到达日期和离开日期,但对我来说最困难的部分是分割部分。我的最终结果需要如下所示:

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
ID、名称、到达日期和离开日期来自特定的表。如何将分割部分添加到现有查询中,以使输出与上面所示类似

在做了一些研究之后,我注意到日历表可能会有所帮助,但我不知道如何在查询中实现它


感谢您的输入。

我认为日历表将是最好的选择。我认为查询看起来是这样的,我将您的表命名为VisitDate,并假设日历表有一个日期字段和一个月字段

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]

这也可以通过一组案例陈述来完成: 让我们制作一些测试数据:

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
根据数据,我让James夫人在7月份到达,停留了几个月,然后在9月份离开,因此你可以看到日期与月份重叠。案例陈述可以转化为一个函数,在报告年度传递,以简化代码,但我只是想展示代码的工作方式

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

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    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
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

分享一些解决方法或查询,通过这些方法您可以生成上述输出。您将在什么基础上分割数据?如果到达日期在月末,而出发日期是下个月的第一个月,那么在这种情况下,计数应转到哪个月?@Surendra Nath GM:计数将转到月份rel返回到到达日期,因为我们计算的是花费的夜晚,而不是花费的天数。我建议将您的查询稍微更改为“从日历c左加入VisitDate d开”…主要是返回所有日期,即使它不在VisitDate表中。我想我需要完全加入,因为我不关心任何不属于Vi的日期sitDate,并且一旦它是完全联接,联接中表的顺序就无关紧要了。当然,这是假设我正确理解了问题的本质。:-哇!感谢您提供答案!我非常感谢。在您提供的第二个备选方案中,输出是以天而不是以夜为单位的。我可以问一下吗我如何在您的代码中对此进行调整?而不是在包含之间使用,只需使用c.CheckDate>=b.ArrivalDate和c.CheckDate