使用列值的排列

时间:2017-05-06 02:52:27

标签: sql oracle oracle12c

我正在尝试从下表

key val
A   10
B   20
C   30
D   40

实现以下结果。列标签按字母顺序显示的所有组合。列总计的组合显示 val 的添加。

label total
A     10
AB    30
ABC   60
ABCD  100
AC    40
AD    50
B     20
BC    50
BCD   90
BD    60
C     30
CD    70
D     40

虽然设法得到一个查询,仍然没有那么说服它。寻找更好的方法来获得相同的结果集。提前谢谢。

with f (rn, key, val) as
(
  select rownum, a.* from
  (
      select 'A' key, 10 val from dual 
      union all select 'B', 20 from dual 
      union all select 'C', 30 from dual 
      union all select 'D', 40 from dual 
--      union all select 'E', 50 from dual
--      union all select 'F', 60 from dual
      order by 1
  ) a
)
,
-- irn, ikey, ival: anchor rownum, key and val to remember the starting row
-- rn, key, val: for the current row in the recursion
-- r1: current label in the recursion
-- r2: combination of anchor key and the current row key in the recursion
-- total: addition of all values for keys in r1
rs(irn, ikey, ival, rn, key, val, r1, r2, total) as
(
  select rn, key, val, rn, key, val, key, null, val from f
  union all
  select rs.irn, rs.ikey, rs.ival, f.rn, f.key, f.val, rs.r1 || f.key, rs.ikey || f.key, rs.total+f.val 
  from rs join f on (f.rn = rs.rn+1)
)
,
-- to add the additional rows required for the r2 col
-- when either r2 is not empty and not the same as r1 in rs
frs(irn, ikey, ival, rn, key, val, r1, r2, total) as
(
  select * from rs
  union all
  select irn, ikey, ival, rn, key, val, r2, r2, ival+val 
  from frs 
  where r2 is not null and r1 != r2
)
select r1, total from frs
order by 1
;

2 个答案:

答案 0 :(得分:4)

这是一种方法 - 使用自Oracle 11.2以来可用的递归子查询因子:

with
-- Begin test data
     test_data ( key, val ) as (
       select 'A', 10 from dual union all
       select 'B', 20 from dual union all
       select 'C', 30 from dual union all
       select 'D', 40 from dual
     ),
-- End of test data (not part of the solution). 
-- SQL query begins with the keyword "with" from above and continues below this line.
     rec_cte ( label, total, last_symbol ) as (
       select key, val, key                                        -- anchor member
         from test_data
       union all
       select r.label || t.key, r.total + t.val, t.key             -- recursive member
         from rec_cte r join test_data t on r.last_symbol < t.key
     )
select   label, total 
from     rec_cte
order by label                         --  if needed
;

<强>输出

LABEL TOTAL
----- -----
A        10
AB       30
ABC      60
ABCD    100
ABD      70
AC       40
ACD      80
AD       50
B        20
BC       50
BCD      90
BD       60
C        30
CD       70
D        40

15 rows selected.

答案 1 :(得分:1)

您可以使用PL/SQL block / Proceduere来实现相同目标。

假设t_perm是你的桌子,这个proc会给你你想要的东西。但目前它正在dbms_output上显示。您可以将其插入表格或通过光标等显示。但这是逻辑

create or replace procedure perm as
v_hold varchar2(20);
v_sum integer:=0;
cursor crs is select * from t_perm;
cursor crs1 is select * from t_perm;
begin
for rec in crs
loop
for rec1 in crs1
    loop
     if rec.key <= rec1.key then
         v_hold:=v_hold||rec1.key;
         v_sum:=v_sum+rec1.val;
         dbms_output.put_line(v_hold||' '||v_sum);
     end if;
    end loop;
v_hold:='';
v_sum:=0;
end loop;
end;

输出

A 10
AB 30
ABC 60
ABCD 100
B 20
BC 50
BCD 90
C 30
CD 70
D 40