0

毎日行われている取引のログを表示しようとしています。私の現在の方法は恥ずかしいほど非効率的であり、はるかに優れた解決策があると確信しています。これが私の現在のクエリです:

select ReaderMACAddress,
count(typeid) as 'Total Transactions',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '05:00:00' and '11:59:59' THEN 1 ELSE 0 END) as 'Morning(5am-12pm)',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '12:00:00' and '17:59:59' THEN 1 ELSE 0 END) as 'AfternoonActivity(12pm-6pm)',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '18:00:00' and '23:59:59' THEN 1 ELSE 0 END) as 'EveningActivity(6pm-12am)',
SUM(CASE WHEN CAST("Timestamp" as TIME) between '00:00:00' and '04:59:59' THEN 1 ELSE 0 END) as 'OtherActivity(12am-5am)'
from Transactions
where ReaderMACAddress = '0014f54033f5'
Group by ReaderMACAddress;

結果を返します:

ReaderMACAddress    Total Transactions  Morning(5am-12pm)   AfternoonActivity(12pm-6pm) EveningActivity(6pm-12am)   OtherActivity(12am-5am)
0014f54033f5               932                269                    431                          232                         0

(ここでアライメントの問題が発生した場合は申し訳ありません)

現時点では、(where句を介して)指定した単一のリーダーのみを確認したいと思います。理想的には、時間セクションが1つの列にあり、結果、つまりカウント関数が2番目の列にあり、次のような結果が得られる場合は、読みやすくなります。

Total Transactions          932
Morning(5am-12pm)           269
AfternoonActivity(12pm-6pm) 431
EveningActivity(6pm-12am)   232
OtherActivity(12am-5am)     0

助けてくれてありがとう:)

4

1 に答える 1

6

最初に計算列について検討しますが、以前の投稿から、スキーマを変更することはできないと思います。では、ビューはどうですか?

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のように総計を提供するものを追加することもできます。SlotNULL

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回以上時間に変換するのですか?

于 2013-03-01T22:05:00.140 に答える