Oracle SQL 查询使用 GROUP BY 汇总统计信息
题
我有一个 Oracle 表,其中的数据如下所示:
ID BATCH STATUS
1 1 0
2 1 0
3 1 1
4 2 0
那是, ID 是主键,每个“批次”将有多行,并且每行在 地位 柱子。还有很多其他专栏,但这些是重要的。
我需要编写一个查询来总结 状态码 对于每个 批;STATUS 列中可以包含三个可能的值:0、1 和 2,我希望输出如下所示:
BATCH STATUS0 STATUS1 STATUS2
1 2 1 0
2 1 0 0
这些数字就是计数;对于批次 1,有
- 2 条记录,其中 地位 设置为 0
- 1 条记录在哪里 地位 被设置为 1,并且
- 没有记录在哪里 地位 设置为 0。
对于第 2 批,有
- 1 条记录在哪里 地位 被设置为 0,并且
- 没有记录在哪里 地位 设置为 1 或 2。
有没有一种方法可以在一个查询中执行此操作,而无需为每个状态代码重写查询?IE。我可以轻松编写这样的查询,并运行它三次:
SELECT batch, COUNT(status)
FROM table
WHERE status = 0
GROUP BY batch
我可以运行它,然后在 status = 1 处再次运行它,然后在 status = 2 处再次运行它,但我希望在一个查询中完成它。
如果它有影响的话,除了 地位 列有 其他 我可能想以同样的方式总结的列 - 我不想在 SELECT 语句之后执行 SELECT 语句并合并所有结果的另一个原因。
解决方案
select batch
, count(case when status=1 then 1 end) status1
, count(case when status=2 then 1 end) status2
, count(case when status=3 then 1 end) status3
from table
group by batch;
这通常称为“枢轴”查询,我写了一篇关于如何动态生成这些查询的文章 在我的博客上.
使用 DECODE 的版本(Oracle 特定但不太详细):
select batch
, count(decode(status,1,1)) status1
, count(decode(status,2,1)) status2
, count(decode(status,3,1)) status3
from table
group by batch;
其他提示
select batch,
sum(select case when status = 0 then 1 else 0 end) status0,
sum(select case when status = 1 then 1 else 0 end) status1,
sum(select case when status = 2 then 1 else 0 end) status2
from table
group by batch
select batch,
sum((decode(status,0,1,0)) status0,
sum((decode(status,1,1,0)) status1,
sum((decode(status,2,1,0)) status2,
from table
group by batch
OP 询问一种方法(SUM)相对于另一种方法(COUNT)是否有任何性能优势。对具有 26K 行的表运行简单测试表明 COUNT 方法明显更快。YMMV。
DECLARE
CURSOR B IS
select batch_id
FROM batch
WHERE ROWNUM < 2000;
v_t1 NUMBER;
v_t2 NUMBER;
v_c1 NUMBER;
v_c2 NUMBER;
v_opn INTEGER;
v_cls INTEGER;
v_btc VARCHAR2(100);
BEGIN
-- Loop using SUM
v_t1 := dbms_utility.get_time;
v_c1 := dbms_utility.get_cpu_time;
FOR R IN B LOOP
FOR R2 IN (SELECT batch_type_code
, SUM(decode(batch_status_code, 'CLOSED', 1, 0)) closed
, SUM(decode(batch_status_code, 'OPEN', 1, 0)) OPEN
, SUM(decode(batch_status_code, 'REWORK', 1, 0)) rework
FROM batch
GROUP BY batch_type_code) LOOP
v_opn := R2.open;
v_cls := R2.closed;
END LOOP;
END LOOP;
v_t2 := dbms_utility.get_time;
v_c2 := dbms_utility.get_cpu_time;
dbms_output.put_line('For loop using SUM:');
dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
-- Loop using COUNT
v_t1 := dbms_utility.get_time;
v_c1 := dbms_utility.get_cpu_time;
FOR R IN B LOOP
FOR R2 IN (SELECT batch_type_code
, COUNT(CASE WHEN batch_status_code = 'CLOSED' THEN 1 END) closed
, COUNT(CASE WHEN batch_status_code = 'OPEN' THEN 1 END) OPEN
, COUNT(CASE WHEN batch_status_code = 'REWORK' THEN 1 END) rework
FROM batch
GROUP BY batch_type_code) LOOP
v_opn := R2.open;
v_cls := R2.closed;
END LOOP;
END LOOP;
v_t2 := dbms_utility.get_time;
v_c2 := dbms_utility.get_cpu_time;
dbms_output.put_line('For loop using COUNT:');
dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
END;
/
这产生了以下输出:
For loop using SUM:
CPU seconds used: 40
Elapsed time: 40.09
For loop using COUNT:
CPU seconds used: 33.26
Elapsed time: 33.34
我重复了几次测试,以消除缓存的影响。我还交换了选择语句。整体结果相似。
编辑:这是我曾经回答过的相同测试工具 类似的问题 和。
不隶属于 StackOverflow