簡體   English   中英

在sql server查詢(存儲過程)中按月分組日期

[英]Grouping dates by month in an sql server query (stored procedure)

我對這個有一點精神障礙。

我有酒店房間的預訂系統,它包含一張桌子

BookingRoomLink
BookingId(FK)
RoomId(FK)
開始日期
結束日期

我想查詢數據以提取每個月的入住率。 我可以手動完成這個(即過去一個月做這樣的事情)。

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

然后我可以對結果或類似情況進行計數,這會給我房間的夜晚“使用”,並在一個月內的房間晚上減去這個。

例如。 10個房間x每月30天= 300個可能的房晚。 使用了150(來自查詢的結果)= 50%的占用率。

問題

我喜歡將其自動化為存儲過程。

是否有可能將這個分組為特定年份的幾個月?

我如何確保適合處理一個月邊界的預訂?

如果您經常需要這樣做,可以將這些月份和年份部分作為持久計算列添加到表中,並為它們添加索引:

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進行更新 - 每次訪問它們時都不會計算它們 - >快得多而不僅僅是在所有查詢中使用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

您可以將日期“舍入”到該月的第1天,然后再進行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]

您可以使用DATEPART功能獲取月號和組號。

如果您可以向表中添加計算列,請將其值設置為您要使用的月份。 我肯定會選擇“與行存儲”而不是每次計算。

至於跨越幾個月,您將必須決定如何對其進行建模。 如果您預訂了3個月,該怎么辦? 4? 12? 更多?

至於月份,您可以嘗試像200911這樣的6位數值,這樣您就可以輕松地對它們進行排序,但將它們保存在整數字段中。 如果計算了該值,則沒有人能夠對其進行處理。

嘗試:

 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM