WITH T1 AS ( select '5121500' stuno from dual union all select '5121973' stuno from dual union all select '4846456' stuno from dual union all select '4992500' stuno from dual ) select * from t1 ; WITH T AS ( select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5121500' stuno, 11 disp_ord from dual union all select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5121973' stuno, 11 disp_ord from dual union all select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5181999' stuno, 11 disp_ord from dual union all select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5182136' stuno, 11 disp_ord from dual union all select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5201322' stuno, 11 disp_ord from dual union all select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5243210' stuno, 11 disp_ord from dual union all select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5243406' stuno, 11 disp_ord from dual ) select * from t ;
"수강신청" | "봉사활동" | "결과1" | |||||||||
day_gbn | day_gbn_nm | dtime | stuno | disp_ord | stuno | day_gbn | day_gbn_nm | dtime | nm_list | ||
2 | 월 | 1A(08:00) | 5121500 | 11 | 5121500 | 2 | 월 | 1A(08:00) | 5121500, 5121973 | ||
2 | 월 | 1A(08:00) | 5121973 | 11 | 5121973 | "결과2" | |||||
2 | 월 | 1A(08:00) | 5181999 | 11 | 4846456 | day_gbn | day_gbn_nm | dtime | nm_list | ||
2 | 월 | 1A(08:00) | 5182136 | 11 | 4992500 | 2 | 월 | 1A(08:00) | 4846456, 4992500 | ||
2 | 월 | 1A(08:00) | 5201322 | 11 | |||||||
2 | 월 | 1A(08:00) | 5243210 | 11 | |||||||
2 | 월 | 1A(08:00) | 5243406 | 11 |
"수강신청" 테이블이랑 "봉사활동" 테이블을 이용하여서 결과 1은 낼수있엇는데
결과2를 내고싶습니다 즉
"봉사활동" 테이블의 stuno 에 해당하는 학번이 "수강신청" 테이블의 day_gbn, dtime 에 따른
학번의 결과값 즉 5121500, 5212973 의 나머지값인 "봉사활동"의 4846456, 4992500 의 값을 결과 2처럼 보여주고싶습니다
쉽지가않네요 ...
wITH T1 AS
(
select '5121500' stuno from dual union all
select '5121973' stuno from dual union all
select '4846456' stuno from dual union all
select '4992500' stuno from dual
),
t as(
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5121500' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5121973' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5181999' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5182136' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5201322' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5243210' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5243406' stuno, 11 disp_ord from dual
)
select day_gbn,day_gbn_nm,dtime,listagg(stuno,',') within group(order by stuno) nm_list
from (
select distinct aa.stuno,aa.day_gbn,aa.day_gbn_nm,aa.dtime,aa.disp_ord, nvl2(cc.stuno,1,2) gb
from (
select a.stuno,day_gbn,day_gbn_nm,dtime,disp_ord
from t1 a, t b) aa, t1 bb, t cc
where aa.stuno = bb.stuno
and aa.stuno = cc.stuno (+))
group by gb,day_gbn,day_gbn_nm,dtime,disp_ord
;
아래의 쿼리가 결과1을도출해내는 쿼리입니다 보시다시피 쉬워요 ^^
근데 반대의 결과 학생집합을 가져오려니 힘들더라구요 ㅠㅠ
WITH T1 AS
(
select '5121500' stuno from dual union all
select '5121973' stuno from dual union all
select '4846456' stuno from dual union all
select '4992500' stuno from dual
)
,
T AS
(
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5121500' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5121973' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5181999' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5182136' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5201322' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5243210' stuno, 11 disp_ord from dual union all
select '2' day_gbn, '월' day_gbn_nm, '1A(08:00)' dtime, '5243406' stuno, 11 disp_ord from dual
)
select t.day_gbn
, t.DAY_GBN_NM
, t.dtime
, t.disp_ord
, listagg(t1.stuno,',') within group(order by t.day_gbn,t.disp_ord ) as nm_list
, count(t1.stuno)
from t, t1
where t.stuno = t1.stuno(+)
group by t.day_gbn,t.day_gbn_nm, t.dtime, t.disp_ord
order by t.day_gbn, t.disp_ord
;
SELECT t.day_gbn , t.day_gbn_nm , t.dtime , t.disp_ord , LISTAGG(t1.stuno, ',') WITHIN GROUP(ORDER BY t.day_gbn, t.disp_ord) AS nm_list , COUNT(t1.stuno) AS cnt FROM t1 LEFT OUTER JOIN t PARTITION BY (t.day_gbn, t.day_gbn_nm, t.dtime, t.disp_ord) ON t.stuno = t1.stuno WHERE t.stuno IS NULL GROUP by t.day_gbn, t.day_gbn_nm, t.dtime, t.disp_ord ORDER by t.day_gbn, t.disp_ord ;
아우터 조인의 기준이 무었인지 명확하게 판단해야 하는 문제인데요.
언듯 보면 t1 을 기준으로 t 에 없는 것을 나와야 하므로 t1 이 기준인 듯 보이지만
t 에 없는 것을 조회하면서 t 의 값이 조회되어야만 하는 모순에 빠지게 됩니다.
결국 기준은 t1 이 아니라는 거구요.
기준은 t1 + t 의 크로스조인 조합입니다.
t1의 코드와 t의 요일이 함께 조합된 결과 집합이 기준이 되어야 합니다.
SELECT x.day_gbn , x.day_gbn_nm , x.dtime , x.disp_ord , LISTAGG(x.stuno, ',') WITHIN GROUP(ORDER BY x.day_gbn, x.disp_ord) AS nm_list , COUNT(x.stuno) AS cnt FROM (SELECT day_gbn, day_gbn_nm, dtime, disp_ord , stuno FROM t1 a , (SELECT DISTINCT day_gbn, day_gbn_nm, dtime, disp_ord FROM t) b ) x , t y WHERE x.day_gbn = y.day_gbn (+) AND x.day_gbn_nm = y.day_gbn_nm(+) AND x.dtime = y.dtime (+) AND x.disp_ord = y.disp_ord (+) AND x.stuno = y.stuno (+) AND y.stuno IS NULL GROUP BY x.day_gbn, x.day_gbn_nm, x.dtime, x.disp_ord ORDER BY x.day_gbn, x.disp_ord ;
위 쿼리의 과정을 살펴보면
1. 기준집합을 얻기 위해 t 를 Distinct 하고 t1 과 Cross Join 합니다.
2. 그리고 그결과를 기준으로 t 를 아우터 조인합니다.
3. 아우터 조인 결과가 없는(y.stuno IS NULL) 것만 걸러내고
4. 그룹바이로 집계하여 마무리합니다.
하지만 t 테이블을 2번이나 읽고 있습니다.
PARTITION OUTER JOIN 을 이용하면 1번만 읽고도 이 모순을 해결할 수 있습니다.
t1 을 기준으로 해서 t 를 아우터 조인 거는데, t 의 그룹별로 아우터 조인을 하는 구문입니다.