在sql server查询(存储过程)中按月分组日期

时间:2009-11-16 18:06:54

标签: sql sql-server sql-server-2008 date-manipulation

我对这个有一点精神障碍。

我有酒店房间的预订系统,它包含一个表格

BookingRoomLink
BookingId(FK)
RoomId(FK)
START_DATE
END_DATE

我想查询数据以提取每个月的入住率。 我可以手动完成这个(即过去一个月做这样的事情)。

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

然后我可以对结果或类似情况进行计数,这会给我“使用”房间的夜晚,并在一个月内的房间晚上减去这个。

EG。 10个房间 x每月30天=可能有300个房晚。使用了150(来自查询的结果)= 50%的占用率。

问题

我想将其自动化为存储过程。

是否有可能将这个分组为特定年份的几个月?

我如何确保适合处理一个月边界的预订?

6 个答案:

答案 0 :(得分:3)

如果您需要经常这样做,您可以将这些月份和年份部分作为持久计算列添加到您的表中,并为它们添加索引:

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

您现在可以选择这些新的计算列,在WHERE子句中使用它们,按这些列使用GROUP - 它们将始终基于Start_Date和End_Date进行更新 - 每次访问它们时都不会计算它们 - &GT;比在所有查询中使用DATEPART快得多!

答案 1 :(得分:3)

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

答案 2 :(得分:2)

您可以将日期“舍入”到该月的第一天,然后再将GROUP BY打开。与使用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]

答案 3 :(得分:0)

您可以使用DATEPART功能获取月号和分组号。

答案 4 :(得分:0)

如果您可以向表中添加计算列,请将其值设置为您要使用的月份。我肯定会选择“与行存储”而不是每次计算。

至于跨越几个月,您必须决定如何对其进行建模。如果您预订了3个月,该怎么办? 4? 12?更?

至于月份,您可以尝试像200911这样的6位数值,这样您就可以轻松地对它们进行排序,但将它们保存在整数字段中。如果计算了这个值,那么任何人都无法使用它。

答案 5 :(得分:0)

尝试:

 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)