[英]Grouping dates by month in an sql server query (stored procedure)
Im having a bit of a mental block on this one. 我对这个有一点精神障碍。
I got booking system for hotel rooms and it contains a table as so 我有酒店房间的预订系统,它包含一张桌子
BookingRoomLink BookingRoomLink
BookingId (FK) BookingId(FK)
RoomId (FK) RoomId(FK)
Start_Date 开始日期
End_Date 结束日期
I'd like to query the data to extract occupancy levels for each month. 我想查询数据以提取每个月的入住率。 I could do this manually (ie for the past month do something like this).
我可以手动完成这个(即过去一个月做这样的事情)。
SELECT BookingRoomLink.Start_Date,
BookingRoomLink.End_Date,
DATEDIFF("d", BookingRoomLink.Start_Date, BookingRoomLink.End_Date) as RoomNights
FROM BookingRoomLink
WHERE BookingRoomLink.Start_Date >= dateadd(m, -1, getdate())
AND BookingRoomLink.End_Date <= GETDATE()
Then i can do a count on the results or similar which would give me the room nights "used" and subtract this against the room nights available in a month. 然后我可以对结果或类似情况进行计数,这会给我房间的夜晚“使用”,并在一个月内的房间晚上减去这个。
Eg. 例如。 10 rooms x 30 days in the month = 300 possible room nights available.
10个房间x每月30天= 300个可能的房晚。 150 used (result from query) = 50% occupancy.
使用了150(来自查询的结果)= 50%的占用率。
The problem 问题
Id like to automate this into a stored procedure. 我喜欢将其自动化为存储过程。
Is it possible to group this into months for a given year? 是否有可能将这个分组为特定年份的几个月?
How would I ensure that bookings which overlap a month boundry are suitable handled? 我如何确保适合处理一个月边界的预订?
If you need to do this often, you could add those month and year parts as persisted computed columns to your table, and put an index on them: 如果您经常需要这样做,可以将这些月份和年份部分作为持久计算列添加到表中,并为它们添加索引:
ALTER TABLE dbo.BookingRoomLink
ADD StartMonth AS MONTH(Start_Date) PERSISTED
ALTER TABLE dbo.BookingRoomLink
ADD StartYear AS Year(Start_Date) PERSISTED
ALTER TABLE dbo.BookingRoomLink
ADD EndMonth AS MONTH(End_Date) PERSISTED
ALTER TABLE dbo.BookingRoomLink
ADD EndYear AS Year(End_Date) PERSISTED
You could now select these new computed columns, use them in a WHERE clause, GROUP by those columns - and they'll always be up to date based on Start_Date and End_Date - they're not computed everytime you access them --> much faster than just using DATEPART
in all your queries! 您现在可以选择这些新的计算列,在WHERE子句中使用它们,按这些列使用GROUP - 它们将始终基于Start_Date和End_Date进行更新 - 每次访问它们时都不会计算它们 - >快得多而不仅仅是在所有查询中使用
DATEPART
!
WITH (
SELECT 0
UNION ALL
SELECT m + 1
FROM mon
WHERE m < 11
),
yr (y) AS
(
SELECT CAST('1990-01-01' AS DATETIME)
UNION ALL
SELECT DATEADD(year, 1, y)
FROM yr
WHERE y <= GETDATE()
),
dates (smy, emy) AS
(
SELECT DATEADD(month, m, y), DATEADD(month, m + 1, y)
FROM yr
CROSS JOIN
mon
),
diffs (smy, emy, days) AS
(
SELECT smy, emy, DATEDIFF(day, smy, emy)
FROM dates
)
SELECT smy,
roomId,
CAST(SUM(DATEDIFF(day,
CASE WHEN start_date < smy THEN smy ELSE start_date END,
CASE WHEN end_date > emy THEN emy ELSE end_date END
)) AS FLOAT) / days
FROM diffs
JOIN bookings
ON start_date < emy
AND end_date >= smy
GROUP BY
roomId, smy, emy, days
You could "Round" the date to the 1st of the month, and then GROUP BY on that. 您可以将日期“舍入”到该月的第1天,然后再进行GROUP BY。 Similar to using DatePart, but you still have a valid date, so you can use a Date Range in the WHERE clause before or after doing the Grouping.
与使用DatePart类似,但您仍然具有有效日期,因此您可以在执行分组之前或之后在WHERE子句中使用日期范围。
SELECT [Date] = DATEADD(Month, DATEDIFF(Month, 0, Start_Date), 0), -- 1st of the month [Bookings] = COUNT(*) FROM BookingRoomLink GROUP BY DATEADD(Month, DATEDIFF(Month, 0, Start_Date), 0) ORDER BY [Date]
您可以使用DATEPART功能获取月号和组号。
If You can add a computed column to your table, make its value the month you want to use. 如果您可以向表中添加计算列,请将其值设置为您要使用的月份。 I would definitely choose "store with row" vs. compute each time.
我肯定会选择“与行存储”而不是每次计算。
As for spanning months, you'll have to decide how you want to model that. 至于跨越几个月,您将必须决定如何对其进行建模。 What if you have a reservation that spans 3 months?
如果您预订了3个月,该怎么办? 4?
4? 12?
12? More?
更多?
As for the month, you might try a 6-digit value like 200911 so you can easily sort them but keep them in an integer field. 至于月份,您可以尝试像200911这样的6位数值,这样您就可以轻松地对它们进行排序,但将它们保存在整数字段中。 If the value is computed, no one will be able to doink with it.
如果计算了该值,则没有人能够对其进行处理。
Try: 尝试:
Select DateName(month, start_Date) +
DateName(Year, Start_Date) as MonthName,
Sum(DateDiff(Day, Start_Date,
Case DateDiff(Month, Start_Date, End_Date)
When 0 Then End_Date
Else DateAdd(day, -day(Start_Date),
DateAdd(day, DateDiff(day, 0, Start_Date), 0)) Bookings
From BookingRoomLink
Group By DateName(month, start_Date) + DateName(Year, Start_Date)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.