假设以下简化模式:
create table main_table
(
a number,
b number,
c number
);
create table other_table
(
c number,
d number
)
现在,我要实现的目标: 我对main_table有一个查询,该查询按a,b分组。 我需要在select子句的子查询中使用“ c的所有值”,以从其他表中获取一些数据。 不幸的是,我无法加入另一个桌子。
伪代码为:
select mt.a,
mt.b,
(select /* some aggregated value */
from other_table ot
where ot.c in (all_values_of_c_within_group)
)
from main table mt
group by mt.a, mt.b
我知道有两种方法可以处理此问题:
/*(...)*/
(select /* some_aggregated_value */
from other_table ot
where instr(',' || listagg(
to_char(mt.c), ',') within group (order by 1),
',' || ot.c) > 0
)
/*(...)*/
但这只是糟糕的代码,它会自动阻止在other_table.c上使用任何潜在的现有索引。
是否有一种语法可以正确获取“组内所有列的值?
答案 0 :(得分:1)
没有一些数据和预期结果尚不清楚您要实现的目标,但我认为您可以使用集合来完成您想做的事情:
Oracle 11g R2架构设置:
create table main_table( a, b, c ) AS
SELECT 1, 1, 1 FROM DUAL UNION ALL
SELECT 1, 1, 2 FROM DUAL UNION ALL
SELECT 1, 1, 3 FROM DUAL
/
create table other_table( c, d ) AS
SELECT 1, 4 FROM DUAL UNION ALL
SELECT 3, 6 FROM DUAL UNION ALL
SELECT 5, 8 FROM DUAL
/
CREATE TYPE number_table AS TABLE OF NUMBER
/
查询1 :
SELECT a,
b,
( SELECT LISTAGG( d, ',' ) WITHIN GROUP ( ORDER BY d )
FROM other_table
WHERE c MEMBER OF m.cs
) ds
FROM (
SELECT a,
b,
CAST( COLLECT( c ) AS number_table ) AS cs
FROM main_table
GROUP BY a, b
) m
Results :
| A | B | DS |
|---|---|-----|
| 1 | 1 | 4,6 |
查询2 :但是使用LEFT OUTER JOIN
似乎更简单:
SELECT a,
b,
LISTAGG( d, ',' ) WITHIN GROUP ( ORDER BY d ) ds
FROM main_table m
LEFT OUTER JOIN other_table o
ON ( m.c = o.c )
GROUP BY a, b
Results :
| A | B | DS |
|---|---|-----|
| 1 | 1 | 4,6 |
答案 1 :(得分:1)
您也许可以汇总子查询,例如以sum作为聚合函数:
select mt.a,
mt.b,
sum(
(select d
from other_table ot
where ot.c = mt.c)
) as sum_d
from main_table mt
group by mt.a, mt.b;
包含一些虚构数据:
insert into main_table values (1, 2, 3);
insert into main_table values (1, 2, 4);
insert into main_table values (2, 3, 4);
insert into main_table values (2, 3, 5);
insert into main_table values (2, 3, 6);
insert into other_table values (3, 10);
insert into other_table values (4, 11);
insert into other_table values (5, 12);
insert into other_table values (6, 13);
该查询给出的:
A B SUM_D
---------- ---------- ----------
2 3 36
1 2 21
正如您所指出的,还有一行:
insert into main_table values (2, 3, 4);
该查询多次计算匹配的c
的{{1}}值,因此您得到的是47而不是36:
d
您可以添加 A B SUM_D
---------- ---------- ----------
2 3 47
1 2 21
:
distinct
这假设select mt.a,
mt.b,
sum(distinct
(select d
from other_table ot
where ot.c = mt.c)
) as sum_d
from main_table mt
group by mt.a, mt.b;
A B SUM_D
---------- ---------- ----------
1 2 21
2 3 36
或至少c
的组合在c, d
中是唯一的。
答案 2 :(得分:0)
这应该可行,并且不应该像Alex的回答那样对other_table
施加唯一性要求。
select mt.a,
mt.b,
(select sum(d) /* some aggregated value */
from other_table ot
where ot.c in ( SELECT mt2.c
FROM main_table mt2
WHERE mt2.a = mt.a AND mt2.b = mt.b
)
) agg
from main_table mt
group by mt.a, mt.b;
每个组必须再次转到main_table
,但是考虑到您已经在访问这些记录,我们应该讨论的是额外的逻辑I / O,而不是额外的物理I / O。
使用Alex Poole的测试数据(带有重复的MAIN_TABLE
行),我在12c中得到了这一点:
+---+---+-----+
| A | B | AGG |
+---+---+-----+
| 2 | 3 | 36 |
| 1 | 2 | 21 |
+---+---+-----+