假设我在Oracle数据库中有以下表格:
TBL_A
包含ID
,C_1
,C_2
,C_3
,...,C_20
列(主键:{{ 1}})ID
包含TBL_B
,ID
,A_ID
,C_1
,C_2
,...,C_3
列(外键C_20
引用A_ID
)TBL_A.ID
,TBL_C
等与TBL_D
具有相同的通用布局现在,我正在尝试根据TBL_B
的行和同时对行进行分组来构建报告,例如从其他表(TBL_A
,TBL_B
等)汇总不同的数据(总和,计数,最小/最大/平均值等),其中满足一些额外的标准。
我的问题可能归结为如果主要查询是基于TBL_C
使用{{1}的选择,如何(如果可能的话)连接子查询中TBL_x
的数据例如,像这样:
TBL_A
即使Oracle不会执行此代码(ORA-00979,a.id不是GROUP BY表达式),我希望查询的目的应该是显而易见的。在这种情况下,我需要一个四列结果集:
GROUP BY
。select a.c_1,
count(a.id) as cnt, -- number of matches in TBL_A for this group
(select count(*) from tbl_b b where b.a_id = a.id and b.c_1 = 2) as b_cnt,
(select sum(c_5) from tbl_c c where c.a_id = a.id and c.c_3 = 3) as c_sum
from tbl_a a
where ...
group by a.c_1;
的行数。TBL_A.C_1
中TBL_A
和TBL_B
引用此组中包含的C_1 = 2
中任意行的行数。A_ID
中行TBL_A
的总和C_5
和TBL_B
指的是此群组中包含的C_3 = 3
中的任何行。< / LI>
醇>
我知道我可以重写子查询,以便在where子句中重复group-by列,例如像这样只有一个列:
A_ID
但是在这种情况下,我必须在所有子查询中重复所有group by列和外部where子句,因为实际上where子句相当长,并且我在group by子句中有两个列,以及许多子查询引用与TBL_A
具有不同关系的不同表,SQL语句可能最终会成为一个完整的混乱。
在Oracle中是否真的不可能在子查询中使用组内各个行的值,就像我在第一个示例中尝试的那样(select a.c_1,
(select count(*) from tbl_b b, tbl_a a2
where a2.c_1 = a.c_1 and b.a_id = a2.id and b.c_1 = 2) as b_cnt_2
from tbl_a a
where ...
group by a.c_1;
和TBL_A
都失败)?我还考虑过使用b.a_id = a.id
做一些技巧,但Oracle似乎不接受子查询子句中的任何聚合函数(这里不允许使用ORA-00934组函数)。我会理解外部where子句中的限制,但不是为什么在子查询where子句中不允许这样做。
我尝试通过将附加表(b.a_id in a.id
,listagg
等)与外部联接而不是编写子查询来实现查询,但这会扩展结果(创建所有的几个组合)在分组之前涉及表格,以便聚合函数不止一次地考虑同一行。例如。在TBL_B
中有两行引用TBL_C
中的一行,TBL_B
会计算TBL_A
中的同一行两次。
任何有想法如何进行的人?
答案 0 :(得分:2)
可能最简单的方法是使用子查询或CTE:
with a as (
select a.c_1, a.id,
count(a.id) as cnt, -- number of matches in TBL_A for this group
(select count(*) from tbl_b b where b.a_id = a.id and b.c_1 = 2) as b_cnt,
(select sum(c_5) from tbl_c c where c.a_id = a.id and c.c_3 = 3) as c_sum
from tbl_a a
where ...
group by a.id
)
select a.c_1,
sum(cnt) as cnt,
sum(b_cnt) as b_cnt,
sum(c_sum) as c_sum
from a
group by a.c_1;
这适用于大多数聚合函数。如果你有avg()
,那么分别计算和计算,并将总数除以平均值。如果您有count(distinct)
,那么这将无效。你的问题没有这些。
答案 1 :(得分:0)
如果我了解您正在尝试正确执行的操作,则可以获取派生表中每个a.id的聚合,将这些聚合连接到表a,然后使用sum
再次聚合
select
a.c_1
count(a.id),
coalesce(sum(b_count),0) b_cnt,
coalesce(sum(c_sum),0) c_sum
from tbl_a a
left join (
select a_id, count(*) b_count from tbl_b
where c_1 = 2
group by a_id
) b on b.a_id = a.id
left join (
select a_id, sum(c_5) c_sum from tbl_c
where c_3 = 3
group by a_id
) c on c.a_id = a.id
where ...
group by a.c_1