在子查询条件中使用组内行的值

时间:2014-09-23 19:17:04

标签: sql oracle group-by subquery

假设我在Oracle数据库中有以下表格:

  • TBL_A包含IDC_1C_2C_3,...,C_20列(主键:{{ 1}})
  • ID包含TBL_BIDA_IDC_1C_2,...,C_3列(外键C_20引用A_ID
  • TBL_A.IDTBL_C等与TBL_D具有相同的通用布局

现在,我正在尝试根据TBL_B的行和同时对行进行分组来构建报告,例如从其他表(TBL_ATBL_B等)汇总不同的数据(总和,计数,最小/最大/平均值等),其中满足一些额外的标准。

我的问题可能归结为如果主要查询是基于TBL_C使用{{1}的选择,如何(如果可能的话)连接子查询中TBL_x的数据例如,像这样:

TBL_A

即使Oracle不会执行此代码(ORA-00979,a.id不是GROUP BY表达式),我希望查询的目的应该是显而易见的。在这种情况下,我需要一个四列结果集:

  1. GROUP BY
  2. 的所有不同值
  3. 此群组中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; 的行数。
  4. TBL_A.C_1TBL_ATBL_B引用此组中包含的C_1 = 2中任意行的行数。
  5. A_ID中行TBL_A的总和C_5TBL_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.idlistagg等)与外部联接而不是编写子查询来实现查询,但这会扩展结果(创建所有的几个组合)在分组之前涉及表格,以便聚合函数不止一次地考虑同一行。例如。在TBL_B中有两行引用TBL_C中的一行,TBL_B会计算TBL_A中的同一行两次。

    任何有想法如何进行的人?

2 个答案:

答案 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