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

(抱歉这里有任何对齐问题)

目前我只想查看我指定的单个 Reader(通过 where 子句)。理想情况下,如果时间部分在单列中并且结果(即计数函数)在第二列中会更容易阅读,从而产生如下结果:

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 只执行一次,为什么要转换为时间 4 次以上?

于 2013-03-01T22:05:00.140 回答