【发布时间】:2012-07-16 14:50:21
【问题描述】:
我在 SO 上看到了 lot of questions,关于如何在 SQL 查询中按范围对数据进行分组。
具体情况各不相同,但每种情况的一般潜在问题是按一系列值而不是GROUP BY 列中的每个离散值进行分组。换句话说,按比您存储在数据库表中的粒度更精确的粒度进行分组。
这在现实世界中经常出现在生成直方图、日历表示、数据透视表和其他定制报告输出等内容时。
一些示例数据(不相关的表格):
| OrderHistory | | Staff |
--------------------------- ------------------------
| Date | Quantity | | Age | Name |
--------------------------- ------------------------
|01-Jul-2012 | 2 | | 19 | Barry |
|02-Jul-2012 | 5 | | 53 | Nigel |
|08-Jul-2012 | 1 | | 29 | Donna |
|10-Jul-2012 | 3 | | 26 | James |
|14-Jul-2012 | 4 | | 44 | Helen |
|17-Jul-2012 | 2 | | 49 | Wendy |
|28-Jul-2012 | 6 | | 62 | Terry |
--------------------------- ------------------------
现在假设我们要使用OrderHistory 表的Date 列按周分组,即7 天范围。或者也许将Staff 分组为 10 岁年龄段:
| Week | QtyCount | | AgeGroup | NameCount |
-------------------------------- -------------------------
|01-Jul to 07-Jul | 7 | | 10-19 | 1 |
|08-Jul to 14-Jul | 8 | | 20-29 | 2 |
|15-Jul to 21-Jul | 2 | | 30-39 | 0 |
|22-Jul to 28-Jul | 6 | | 40-49 | 2 |
-------------------------------- | 50-59 | 1 |
| 60-69 | 1 |
-------------------------
GROUP BY Date 和 GROUP BY Age 自己不会这样做。
我看到的最常见的答案(没有一个始终被评为“正确”)是使用以下一项或多项:
- 一堆
CASE语句,每个分组一个 - 一堆
UNION查询,每个分组有不同的WHERE子句 - 当我使用 SQL Server 时,
PIVOT()andUNPIVOT() - 使用子选择、临时表或视图构造的两阶段查询
是否存在处理此类查询的既定通用模式?
【问题讨论】:
-
CTE 通常用于即时生成范围表。然后将结果连接到正在汇总的数据中。
-
出于多种原因,您不应该存储像“年龄”这样的派生值 - 毕竟,它需要每年更新,在一年中的某个(可能未知)时间点.更好地存储
birthday并即时计算一个人的年龄。 -
@X-Zero 我们确实这样做了,这只是为了消除从“生日”计算“年龄”的步骤(这本身就是一个问题!)。
-
... 因为人实际上是在某个特定的时刻出生的,但通常引用它时没有时间信息;人们不担心时区,他们只处理“观察到的”(太阳)日。
标签: sql sql-server design-patterns group-by