SQL Serverクエリ(ストアドプロシージャ)の月ごとの日付をグループ化する
-
20-09-2019 - |
質問
私はこれに少し精神的なブロックを持っています。
ホテルの部屋用の予約システムを手に入れましたが、テーブルが含まれています。
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()
それから、私は結果などを頼りにすることができます。これは、「使用されている」部屋の夜を与えて、1か月で利用可能な部屋の夜に対してこれを減算します。
例えば。 10室x月の30日= 300室の夜の夜。 150使用(クエリの結果)= 50%の占有。
問題
idはこれをストアドプロシージャに自動化するのが好きです。
これを特定の年に数か月にグループ化することは可能ですか?
1か月の境界が重複する予約が適切に処理されるようにするにはどうすればよいですか?
解決
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
他のヒント
これを頻繁に行う必要がある場合は、それらの月と年のパーツを永続化された計算列としてテーブルに追加して、それらにインデックスを置くことができます。
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
これらの新しい計算された列を選択し、句でそれらを使用することができます。それらの列によってグループをグループ化できます - そして、それらはstart_dateとend_dateに基づいて常に最新のものになります - それらにアクセスするたびに計算されません - >はるかに高速単に使用するよりも DATEPART
すべてのクエリで!
日付を月の1日まで「締めくく」、それをグループ化することができます。 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 その数で月数とグループを取得する機能。
計算された列をテーブルに追加できる場合は、その価値を使用したい月にしてください。私は間違いなく「row with row with row」とコンピューティートを選択します。
数か月に関しては、それをどのようにモデル化するかを決定する必要があります。 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)