SQL Server查询将花费的夜数拆分为相应的“月”列
我使用的是SQL Server 2012,我需要编写一个查询,将到达日期和离开日期之间的差异(即花费的夜数)拆分,并将结果发布到相应的月份列中 我已经知道如何编写查询来获取我的到达日期和离开日期,但对我来说最困难的部分是分割部分。我的最终结果需要如下所示: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
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