您要做的是一个透视操作,SQL 语法不直接支持它。但是,它并不太复杂,并且在概念上涉及 2 个步骤:
- 将数据“放大”为多列,原始数据集中每行一行。这通常使用 CASE WHEN ... ELSE ... END 或偶尔使用函数(如 oracle 中的 decode() )来完成。我将在下面的示例中使用 CASE WHEN,因为它同样适用于大多数 RDBMS
- 使用 GROUP BY 和聚合函数(SUM、MIN、MAX 等)将许多行折叠到所需的输出行集中。
我正在使用这个数据集作为示例:
mysql> select * from foo;
+------+------+---------+
| uid | id | type |
+------+------+---------+
| 1 | 1 | product |
| 1 | 2 | product |
| 1 | 3 | service |
| 1 | 4 | product |
| 1 | 5 | product |
| 2 | 6 | service |
| 1 | 7 | order |
| 2 | 8 | invoice |
| 2 | 9 | product |
+------+------+---------+
第 1 步是“炸毁”数据集:
select uid
, case when type = 'product' then 1 else 0 end as is_product
, case when type = 'service' then 1 else 0 end as is_service
, case when type = 'invoice' then 1 else 0 end as is_invoice
, case when type = 'order' then 1 else 0 end as is_order
from foo;
这使:
+------+------------+------------+------------+----------+
| uid | is_product | is_service | is_invoice | is_order |
+------+------------+------------+------------+----------+
| 1 | 1 | 0 | 0 | 0 |
| 1 | 1 | 0 | 0 | 0 |
| 1 | 0 | 1 | 0 | 0 |
| 1 | 1 | 0 | 0 | 0 |
| 1 | 1 | 0 | 0 | 0 |
| 2 | 0 | 1 | 0 | 0 |
| 1 | 0 | 0 | 0 | 1 |
| 2 | 0 | 0 | 1 | 0 |
| 2 | 1 | 0 | 0 | 0 |
+------+------------+------------+------------+----------+
接下来,我们在每个日期的输出中折叠到一行,并对每个 is_* 列求和,使用或初始查询作为内联视图(也称为“子查询”):
select uid
, sum(is_product) as count_product
, sum(is_service) as count_service
, sum(is_invoice) as count_invoice
, sum(is_order) as count_order
from (
select uid
, case when type = 'product' then 1 else 0 end as is_product
, case when type = 'service' then 1 else 0 end as is_service
, case when type = 'invoice' then 1 else 0 end as is_invoice
, case when type = 'order' then 1 else 0 end as is_order
from foo
) x
group by uid;
(还请注意,您可以将这两个查询合并为一个,尽管为了清楚起见,我在这里分别显示它们;至少在 MySQL 中,这似乎导致执行计划更简单,这通常意味着执行速度更快——与往常一样,测试你在真实数据集上的 SQL 性能,不要相信我的话!)
这给了我们:
+------+---------------+---------------+---------------+-------------+
| uid | count_product | count_service | count_invoice | count_order |
+------+---------------+---------------+---------------+-------------+
| 1 | 4 | 1 | 0 | 1 |
| 2 | 1 | 1 | 1 | 0 |
+------+---------------+---------------+---------------+-------------+
这是期望的结果。