最初に計算列について検討しますが、以前の投稿から、スキーマを変更することはできないと思います。では、ビューはどうですか?
CREATE VIEW dbo.GroupedReaderView
AS
SELECT ReaderMACAddress,
Slot = CASE WHEN t >= '05:00' AND t < '12:00' THEN 1
WHEN t >= '12:00' AND t < '18:00' THEN 2
WHEN t >= '18:00' THEN 3 ELSE 4 END
FROM
(
SELECT ReaderMACAddress, t = CONVERT(TIME, [Timestamp])
FROM dbo.Transactions
) AS x;
これで、MACアドレスごとのクエリがはるかに簡単になります。
SELECT Slot, COUNT(*)
FROM dbo.GroupedReaderView
WHERE ReaderMACAddress = '00...'
GROUP BY Slot;
これにより、次のような結果が得られます。
1 269
2 431
3 232
4 0
また、列が次WITH ROLLUP
のように総計を提供するものを追加することもできます。Slot
NULL
SELECT Slot, COUNT(*)
FROM dbo.GroupedReaderView
WHERE ReaderMACAddress = '00...'
GROUP BY Slot
WITH ROLLUP;
降伏する必要があります:
1 269
2 431
3 232
4 0
NULL 932
また、必要に応じて、プレゼンテーション層にスロットごとにラベルを追加するなど、ピボットすることができます。
この方法で行うこともできます。これにより、ビューがより冗長になり、直接クエリを実行すると多くの余分なデータが取得されます。また、文字列でグループ化するのは少し効率的ではありません。
CREATE VIEW dbo.GroupedReaderView
AS
SELECT ReaderMACAddress,
Slot = CASE WHEN t >= '05:00' AND t < '12:00' THEN
'Morning(5am-12pm)'
WHEN t >= '12:00' AND t < '18:00' THEN
'Afternoon(12pm-6pm)'
WHEN t >= '18:00' THEN
'Evening(6pm-12am)'
ELSE
'Other(12am-5am)'
END
FROM
(
SELECT ReaderMACAddress, t = CONVERT(TIME, [Timestamp])
FROM dbo.Transactions
) AS x;
これらは必ずしもあなたが持っているものより効率的ではありませんが、繰り返しが少なく、目には簡単です。:-)
また、ビューを作成したくない(または作成できない)場合は、それをサブクエリに入れることができます。
SELECT Slot, COUNT(*)
FROM
(
SELECT ReaderMACAddress,
Slot = CASE WHEN t >= '05:00' AND t < '12:00' THEN
'Morning(5am-12pm)'
WHEN t >= '12:00' AND t < '18:00' THEN
'Afternoon(12pm-6pm)'
WHEN t >= '18:00' THEN
'Evening(6pm-12am)'
ELSE
'Other(12am-5am)'
END
FROM
(
SELECT ReaderMACAddress, t = CONVERT(TIME, [Timestamp])
FROM dbo.Transactions
) AS x
) AS y
WHERE ReaderMACAddress = '00...'
GROUP BY Slot
WITH ROLLUP;
それでもBETWEENを使用でき、少し冗長ではない可能性がある代替手段:
SELECT Slot, COUNT(*)
FROM
(
SELECT ReaderMACAddress,
Slot = CASE WHEN h BETWEEN 5 AND 11 THEN 'Morning(5am-12pm)'
WHEN h BETWEEN 12 AND 17 THEN 'Afternoon(12pm-6pm)'
WHEN h >= 18 THEN 'Evening(6pm-12am)'
ELSE 'Other(12am-5am)'
END
FROM
(
SELECT ReaderMACAddress, h = DATEPART(HOUR, [Timestamp])
FROM dbo.Transactions
) AS x
) AS y
WHERE ReaderMACAddress = '00...'
GROUP BY Slot
WITH ROLLUP;
アップデート
そのスロットの結果がない場合でも、常に各スロットを含めるには:
;WITH slots(s, label, h1, h2) AS
(
SELECT 1, 'Morning(5am-12pm)' , 5, 11
UNION ALL SELECT 2, 'Afternoon(12pm-6pm)' , 12, 17
UNION ALL SELECT 3, 'Evening(6pm-12am)' , 18, 23
UNION ALL SELECT 4, 'Other(12am-5am)' , 0, 4
)
SELECT s.label, c = COALESCE(COUNT(y.ReaderMACAddress), 0)
FROM slots AS s
LEFT OUTER JOIN
(
SELECT ReaderMACAddress, h = DATEPART(HOUR, [Timestamp])
FROM dbo.Transactions
WHERE ReaderMACAddress = '00...'
) AS y
ON y.h BETWEEN s.h1 AND s.h2
GROUP BY s.label
WITH ROLLUP;
これらすべての場合の鍵は、単純化することであり、繰り返さないことです。SQL Serverがそれを1回だけ実行する場合でも、なぜ4回以上時間に変換するのですか?