조건.
T01 : T02 :
Name Type Name Type
--------- ---- --------- ----
YMD VARCHAR2(8) -년월 YMD VARCHAR2(8)
SITE_CD VARCHAR2(10) -사업장 SITE_CD VARCHAR2(10)
SALE_TY VARCHAR2(4) -판매구분 PROC_AM NUMBER -구매금액
SALE_AM NUMBER -판매금액
위의 TABLE에 다음과 같은 DATA가 존재한다.
T01 : KEY : YMD
YMD SITE_CD SALE SALE_AM
-------- ---------- ---- ---------
19990501 서울 직판 1000
19990501 서울 대리 1300
19990501 부산 직판 900
19990501 부산 대리 1100
19990501 인천 직판 1200
19990501 인천 대리 900
19990502 서울 직판 1200
19990502 서울 대리 1400
19990502 부산 직판 1000
19990502 부산 대리 1200
19990502 인천 직판 1300
19990502 인천 대리 1000
...
생략
T02
YMD SITE_CD PROC_AM
-------- ---------- ---------
19990501 서울 2000
19990501 부산 2100
19990501 인천 2100
19990502 서울 2100
19990502 부산 1900
19990502 인천 1800
19990503 서울 2400
...
생략
금액을 제외한 나머지 COLUMN은 PRIMARY KEY 이다.
T02와 T01은 MASTER/DETAIL 관계이다.
문제를 단순화하기 위하여 다음과 같은 가정을 한다.
가정1:구매물량은 매일 100으로 동일하다.
가정2:당일 구매된 물량은 전량 당일 판매된다.
가정3:직판물량과 대리판매를 통한 물량은 항상 50:50이다.
가정4:금액이 변하는 이유는 매일 구매/판매 단가가 다르기 때문이다.
여러일자 중 1999년 5월1일과 5월2일 만을 생각해보자.
문제1. 1:1 JOIN
년월 사업장별로 구매금액과 판매금액의 차이금액을 이용
구매금액에 대한 비율, 즉 마진율을 백분율로 구해보자.
결과가 다음과 같으면된다.
YMD SITE_CD PERCENT
-------- ---------- ---------
19990501 부산 -5
19990501 서울 15
19990501 인천 0
19990502 부산 16
19990502 서울 24
19990502 인천 28
생각1.
1:1 조인이란 말그대로 JOIN으로 연결되는 KEY가 1:1 로 정확하게
맞는다는 얘기다.
하지만 현재 두 TABLE의 관계는 MASTER/DETAIL 관계로
1:1이 될 수가 없다.
그럼 어떻게 할 것인가?.
1:1 JOIN 의 전형은 아니지만 전체구매금액과 판매금액을 1:1로 연결
하기 위해서는 1:1 JOIN으로 연결되어야 한다.
다른말로 하면 DETAIL의 판매구분을 무시한상태로 연결이 이루어져야
한다는 뜻인데,
무시된다는 뜻은 있어도 없는걸로 여기라는 말이 아니다.
판매구분이 없어야 년월일/사업장 만이 KEY가 되고 그래야만 MASTER
TABLE인 T02와 1:1로 연결을 해 줄 수 있다.
실제로 연결을 해보자.
5월1일자 DATA만을 이용하여 년월/사업장을 JOIN 조건으로 연결하고
구매금액/판매금액의 합을 보자.
미리 답을 보면 다음과 같다.
판매금액
SITE_CD SUM(SALE_AM)
---------- ------------
부산 2000
서울 2300
인천 2100
구매금액
SITE_CD PROC_AM
---------- ---------
부산 2100
서울 2000
인천 2100
년월일과 사업장만을 연결한다면 문장은 다음과 같이 될 것이다.
SELECT A.SITE_CD,
SUM(A.PROC_AM) PROC_AM,
SUM(B.SALE_AM) SALE_AM
FROM T02 A,
T01 B
WHERE B.YMD = '19990501'
AND A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD
GROUP BY
A.SITE_CD
결과는 어떤가?..다음과 같다.
SITE_CD PROC_AM SALE_AM
---------- --------- ---------
부산 4200 2000
서울 4000 2300
인천 4200 2100
판매금액은 원하는 값이 나오지만 구매금액은 2배가 나왔다..
어찌하여 이런일이 일어나는가?.
그 질문에 답하기 전에 분석을 해보자.
위의 문장에서 GROUP BY를 빼고 SUM을 빼보자.
SELECT A.SITE_CD,
A.PROC_AM,
B.SALE_AM
FROM T02 A,
T01 B
WHERE B.YMD = '19990501'
AND A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD
결과는 아래와 같다.
SITE_CD PROC_AM SALE_AM
---------- --------- ---------
부산 2100 900
부산 2100 1100
서울 2000 1000
서울 2000 1300
인천 2100 1200
인천 2100 900
우리는 년월/사업장을 KEY로 가진 T02 와
년월/사업장/판매구분을 KEY로 가진 T01을 년월/사업장으로
연결했다.
T02의 5월1일자에는 3개의 RECORD가 있으며
T01의 5월1일자에는 6개의 RECORD가 있다.
MASTER TABLE인 T02를 기준으로 보면 T02의 한RECORD마다
T01에는 직판/구매 두개의 DETAIL이 존재한다.
결과는 DETAIL의 RECORD 수와 같은 6개가 나온다.
1:M JOIN의 전형이며 이때의 결과는 M이 된다.
우리가 이미 알고 있는 내용을 눈으로 직접 확인해 보았다.
왜 구매금액이 2배가 되었는지에 대한 대답이 저절로 나온다.
6개의 RECORD를 SUM하면 판매금액 입장에서는 맞지만
구매금액 입장에서는 2배로 뻥튀기가 된다.
이 내용은 잠시후에 다룰 문제2 에서 유용하게 이용될것이다.
지금은 2배로 늘어나는 구매금액을 어떻게 바르게 읽어올 것인가?.
즉, 어떻게 1:M을 1:1조인으로 연결해 줄것인가를 해결하고
그것을 이용해 올바른 답을 구하는 일이다.
해법1.
어떻게 판매구분을 무시할 것인가?..와
어떻게 뻥튀기를 방지할 것인가?...는 동일한 문제이고
동일한 해법을 요구한다.즉,
어떻게 뻥튀기를 방지할것인가 하는 해법이 바로
DETAIL의 또하나의 KEY 인 판매구분을
문제를 일으키지 않고 무시할 것인가 하는 문제와 일맥상통한다.
DETAIL인 T01을 T02와 같은 KEY로 변형하자면 년월일/사업장별로
GROUP BY를 하여 KEY를 일치시킨후 JOIN을 걸어주면된다.
GROUP BY를 통해 가공한 DATASET을 INLINE VIEW로 이용하여
MASTER TABLE인 T02와 JOIN을 걸어보자.
아래와 같이..
SELECT A.YMD,
A.SITE_CD,
ROUND(100 * (B.SALE_AM - A.PROC_AM)/B.SALE_AM) PERCENT
FROM T02 A,
(SELECT YMD,SITE_CD,
SUM(SALE_AM) SALE_AM
FROM T01
WHERE YMD BETWEEN '19990501' AND '19990502'
GROUP BY
YMD,SITE_CD
) B
WHERE A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD
T01을 GROUP BY한 B DATASET은 2틀에 걸쳐 6개의 RECORD를 RETURN한다.
YMD SITE_CD SALE_AM
-------- ---------- ---------
19990501 부산 2000
19990501 서울 2300
19990501 인천 2100
19990502 부산 2200
19990502 서울 2600
19990502 인천 2300
T02의 이틀에 걸친 DATA를 보자.
YMD SITE_CD PROC_AM
-------- ---------- ---------
19990501 부산 2100
19990501 서울 2000
19990501 인천 2100
19990502 부산 1900
19990502 서울 2100
19990502 인천 1800
두개의 DATASET이 년월/사업장을 KEY를 정확이 일치한다.
이것을 JOIN 한것이 위의 답이다.
뒷풀이.
1:1 JOIN 문제를 통해서 1:M 조인도 함께 생각해 보았다.
다음문제를 통해 1:M 문제를 다루어 보자.
DATA의 최종결과를 뽑아내기위해서는 한단계씩 밟아가는 과정이
있다.
이 과정을 이해하고 만들어 내는 힘은 많은 생각을 필요로 하고
많은 생각을 하는 능력은 다양한 문제를 통해서 이다.
한번 읽어보고 이해했다고 하기보다는 직접 QUERY를 만들어보고
DATA를 단계별로 분해해 보는 것이 도움이 될 것이다.
문제2.
우리는 조건을 통해서 구매물량이 50:50으로 직판/대리 로
나누어 판매가 된다는 것을 알고 있다.
이번에는 일자/사업장/판매구분 별로 마진율을 구해보자.
결과가 다음과 같이 나오면된다.
YMD SITE_CD SALE A.PROC_AM*0.5 SALE_AM PERCENT
-------- ---------- ---- ------------- --------- ---------
19990501 부산 직판 1050 900 -14
19990501 부산 대리 1050 1100 5
19990501 서울 직판 1000 1000 0
19990501 서울 대리 1000 1300 30
19990501 인천 직판 1050 1200 14
19990501 인천 대리 1050 900 -14
19990502 부산 직판 950 1000 5
19990502 부산 대리 950 1200 26
19990502 서울 직판 1050 1200 14
19990502 서울 대리 1050 1400 33
19990502 인천 직판 900 1300 44
19990502 인천 대리 900 1000 11
해법2.
문제1도 어려운 문제는 아니지만 문제1에서 이미 해법을 제시했기에
문제1을 정독했다면 쉽게 답이 나올 것이다.
두개의 테이블을 조인하되 년월과 사업장으로만 JOIN을 하면
문제1에서 예시한대로 DETAIL에 맞도록 1:M 조인이된다.
GROUP BY 하거나 SUM이 필요 없이 계산식만 이용하면 된다.
다음 문장이 문제의 답이다.
SELECT B.YMD,
B.SITE_CD,
B.SALE_TY,
A.PROC_AM*0.5,
B.SALE_AM,
ROUND(100*(B.SALE_AM-A.PROC_AM*0.5)/(A.PROC_AM*0.5)) PERCENT
FROM T02 A,
T01 B
WHERE B.YMD BETWEEN '19990501' AND '19990502'
AND A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD;
뒷풀이2.
1:1 조인 과 1:M 조인의 차이에 대해서 알아 보았다.
그 결과가 어떠한지도 눈으로 확인해 보았다.
흔히 지나치기 쉬운 오류다.
QUERY되어 결과는 나오는데 그결과가 맞는 답이 아니라는데
심각성이 있다.
조인이 일어나는 과정을 정확히 이해하고 있을 필요가 있다.
문제가 발생해도 왜,어다가 문제인지 조차 모른다면 안될 것이다.
T01 : T02 :
Name Type Name Type
--------- ---- --------- ----
YMD VARCHAR2(8) -년월 YMD VARCHAR2(8)
SITE_CD VARCHAR2(10) -사업장 SITE_CD VARCHAR2(10)
SALE_TY VARCHAR2(4) -판매구분 PROC_AM NUMBER -구매금액
SALE_AM NUMBER -판매금액
위의 TABLE에 다음과 같은 DATA가 존재한다.
T01 : KEY : YMD
YMD SITE_CD SALE SALE_AM
-------- ---------- ---- ---------
19990501 서울 직판 1000
19990501 서울 대리 1300
19990501 부산 직판 900
19990501 부산 대리 1100
19990501 인천 직판 1200
19990501 인천 대리 900
19990502 서울 직판 1200
19990502 서울 대리 1400
19990502 부산 직판 1000
19990502 부산 대리 1200
19990502 인천 직판 1300
19990502 인천 대리 1000
...
생략
T02
YMD SITE_CD PROC_AM
-------- ---------- ---------
19990501 서울 2000
19990501 부산 2100
19990501 인천 2100
19990502 서울 2100
19990502 부산 1900
19990502 인천 1800
19990503 서울 2400
...
생략
금액을 제외한 나머지 COLUMN은 PRIMARY KEY 이다.
T02와 T01은 MASTER/DETAIL 관계이다.
문제를 단순화하기 위하여 다음과 같은 가정을 한다.
가정1:구매물량은 매일 100으로 동일하다.
가정2:당일 구매된 물량은 전량 당일 판매된다.
가정3:직판물량과 대리판매를 통한 물량은 항상 50:50이다.
가정4:금액이 변하는 이유는 매일 구매/판매 단가가 다르기 때문이다.
여러일자 중 1999년 5월1일과 5월2일 만을 생각해보자.
문제1. 1:1 JOIN
년월 사업장별로 구매금액과 판매금액의 차이금액을 이용
구매금액에 대한 비율, 즉 마진율을 백분율로 구해보자.
결과가 다음과 같으면된다.
YMD SITE_CD PERCENT
-------- ---------- ---------
19990501 부산 -5
19990501 서울 15
19990501 인천 0
19990502 부산 16
19990502 서울 24
19990502 인천 28
생각1.
1:1 조인이란 말그대로 JOIN으로 연결되는 KEY가 1:1 로 정확하게
맞는다는 얘기다.
하지만 현재 두 TABLE의 관계는 MASTER/DETAIL 관계로
1:1이 될 수가 없다.
그럼 어떻게 할 것인가?.
1:1 JOIN 의 전형은 아니지만 전체구매금액과 판매금액을 1:1로 연결
하기 위해서는 1:1 JOIN으로 연결되어야 한다.
다른말로 하면 DETAIL의 판매구분을 무시한상태로 연결이 이루어져야
한다는 뜻인데,
무시된다는 뜻은 있어도 없는걸로 여기라는 말이 아니다.
판매구분이 없어야 년월일/사업장 만이 KEY가 되고 그래야만 MASTER
TABLE인 T02와 1:1로 연결을 해 줄 수 있다.
실제로 연결을 해보자.
5월1일자 DATA만을 이용하여 년월/사업장을 JOIN 조건으로 연결하고
구매금액/판매금액의 합을 보자.
미리 답을 보면 다음과 같다.
판매금액
SITE_CD SUM(SALE_AM)
---------- ------------
부산 2000
서울 2300
인천 2100
구매금액
SITE_CD PROC_AM
---------- ---------
부산 2100
서울 2000
인천 2100
년월일과 사업장만을 연결한다면 문장은 다음과 같이 될 것이다.
SELECT A.SITE_CD,
SUM(A.PROC_AM) PROC_AM,
SUM(B.SALE_AM) SALE_AM
FROM T02 A,
T01 B
WHERE B.YMD = '19990501'
AND A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD
GROUP BY
A.SITE_CD
결과는 어떤가?..다음과 같다.
SITE_CD PROC_AM SALE_AM
---------- --------- ---------
부산 4200 2000
서울 4000 2300
인천 4200 2100
판매금액은 원하는 값이 나오지만 구매금액은 2배가 나왔다..
어찌하여 이런일이 일어나는가?.
그 질문에 답하기 전에 분석을 해보자.
위의 문장에서 GROUP BY를 빼고 SUM을 빼보자.
SELECT A.SITE_CD,
A.PROC_AM,
B.SALE_AM
FROM T02 A,
T01 B
WHERE B.YMD = '19990501'
AND A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD
결과는 아래와 같다.
SITE_CD PROC_AM SALE_AM
---------- --------- ---------
부산 2100 900
부산 2100 1100
서울 2000 1000
서울 2000 1300
인천 2100 1200
인천 2100 900
우리는 년월/사업장을 KEY로 가진 T02 와
년월/사업장/판매구분을 KEY로 가진 T01을 년월/사업장으로
연결했다.
T02의 5월1일자에는 3개의 RECORD가 있으며
T01의 5월1일자에는 6개의 RECORD가 있다.
MASTER TABLE인 T02를 기준으로 보면 T02의 한RECORD마다
T01에는 직판/구매 두개의 DETAIL이 존재한다.
결과는 DETAIL의 RECORD 수와 같은 6개가 나온다.
1:M JOIN의 전형이며 이때의 결과는 M이 된다.
우리가 이미 알고 있는 내용을 눈으로 직접 확인해 보았다.
왜 구매금액이 2배가 되었는지에 대한 대답이 저절로 나온다.
6개의 RECORD를 SUM하면 판매금액 입장에서는 맞지만
구매금액 입장에서는 2배로 뻥튀기가 된다.
이 내용은 잠시후에 다룰 문제2 에서 유용하게 이용될것이다.
지금은 2배로 늘어나는 구매금액을 어떻게 바르게 읽어올 것인가?.
즉, 어떻게 1:M을 1:1조인으로 연결해 줄것인가를 해결하고
그것을 이용해 올바른 답을 구하는 일이다.
해법1.
어떻게 판매구분을 무시할 것인가?..와
어떻게 뻥튀기를 방지할 것인가?...는 동일한 문제이고
동일한 해법을 요구한다.즉,
어떻게 뻥튀기를 방지할것인가 하는 해법이 바로
DETAIL의 또하나의 KEY 인 판매구분을
문제를 일으키지 않고 무시할 것인가 하는 문제와 일맥상통한다.
DETAIL인 T01을 T02와 같은 KEY로 변형하자면 년월일/사업장별로
GROUP BY를 하여 KEY를 일치시킨후 JOIN을 걸어주면된다.
GROUP BY를 통해 가공한 DATASET을 INLINE VIEW로 이용하여
MASTER TABLE인 T02와 JOIN을 걸어보자.
아래와 같이..
SELECT A.YMD,
A.SITE_CD,
ROUND(100 * (B.SALE_AM - A.PROC_AM)/B.SALE_AM) PERCENT
FROM T02 A,
(SELECT YMD,SITE_CD,
SUM(SALE_AM) SALE_AM
FROM T01
WHERE YMD BETWEEN '19990501' AND '19990502'
GROUP BY
YMD,SITE_CD
) B
WHERE A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD
T01을 GROUP BY한 B DATASET은 2틀에 걸쳐 6개의 RECORD를 RETURN한다.
YMD SITE_CD SALE_AM
-------- ---------- ---------
19990501 부산 2000
19990501 서울 2300
19990501 인천 2100
19990502 부산 2200
19990502 서울 2600
19990502 인천 2300
T02의 이틀에 걸친 DATA를 보자.
YMD SITE_CD PROC_AM
-------- ---------- ---------
19990501 부산 2100
19990501 서울 2000
19990501 인천 2100
19990502 부산 1900
19990502 서울 2100
19990502 인천 1800
두개의 DATASET이 년월/사업장을 KEY를 정확이 일치한다.
이것을 JOIN 한것이 위의 답이다.
뒷풀이.
1:1 JOIN 문제를 통해서 1:M 조인도 함께 생각해 보았다.
다음문제를 통해 1:M 문제를 다루어 보자.
DATA의 최종결과를 뽑아내기위해서는 한단계씩 밟아가는 과정이
있다.
이 과정을 이해하고 만들어 내는 힘은 많은 생각을 필요로 하고
많은 생각을 하는 능력은 다양한 문제를 통해서 이다.
한번 읽어보고 이해했다고 하기보다는 직접 QUERY를 만들어보고
DATA를 단계별로 분해해 보는 것이 도움이 될 것이다.
문제2.
우리는 조건을 통해서 구매물량이 50:50으로 직판/대리 로
나누어 판매가 된다는 것을 알고 있다.
이번에는 일자/사업장/판매구분 별로 마진율을 구해보자.
결과가 다음과 같이 나오면된다.
YMD SITE_CD SALE A.PROC_AM*0.5 SALE_AM PERCENT
-------- ---------- ---- ------------- --------- ---------
19990501 부산 직판 1050 900 -14
19990501 부산 대리 1050 1100 5
19990501 서울 직판 1000 1000 0
19990501 서울 대리 1000 1300 30
19990501 인천 직판 1050 1200 14
19990501 인천 대리 1050 900 -14
19990502 부산 직판 950 1000 5
19990502 부산 대리 950 1200 26
19990502 서울 직판 1050 1200 14
19990502 서울 대리 1050 1400 33
19990502 인천 직판 900 1300 44
19990502 인천 대리 900 1000 11
해법2.
문제1도 어려운 문제는 아니지만 문제1에서 이미 해법을 제시했기에
문제1을 정독했다면 쉽게 답이 나올 것이다.
두개의 테이블을 조인하되 년월과 사업장으로만 JOIN을 하면
문제1에서 예시한대로 DETAIL에 맞도록 1:M 조인이된다.
GROUP BY 하거나 SUM이 필요 없이 계산식만 이용하면 된다.
다음 문장이 문제의 답이다.
SELECT B.YMD,
B.SITE_CD,
B.SALE_TY,
A.PROC_AM*0.5,
B.SALE_AM,
ROUND(100*(B.SALE_AM-A.PROC_AM*0.5)/(A.PROC_AM*0.5)) PERCENT
FROM T02 A,
T01 B
WHERE B.YMD BETWEEN '19990501' AND '19990502'
AND A.YMD = B.YMD
AND A.SITE_CD = B.SITE_CD;
뒷풀이2.
1:1 조인 과 1:M 조인의 차이에 대해서 알아 보았다.
그 결과가 어떠한지도 눈으로 확인해 보았다.
흔히 지나치기 쉬운 오류다.
QUERY되어 결과는 나오는데 그결과가 맞는 답이 아니라는데
심각성이 있다.
조인이 일어나는 과정을 정확히 이해하고 있을 필요가 있다.
문제가 발생해도 왜,어다가 문제인지 조차 모른다면 안될 것이다.
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
46 | 빠진이빨찾기 II | 운영자 | 2002.09.18 | 3067 |
45 | 빠진이빨찾기 | 운영자 | 2002.09.18 | 3122 |
44 | 순환참조에서의 상위코드로집계 | 운영자 | 2002.09.18 | 3226 |
43 | CONNECT BY의 SORT와 JOIN | 운영자 | 2002.09.18 | 2811 |
42 | REPORT 양식맞추기4 | 운영자 | 2002.09.18 | 2597 |
41 | REPORT 양식 맞추기 III | 운영자 | 2002.09.18 | 3015 |
40 | REPORT 양식 맞추기 II | 운영자 | 2002.09.18 | 2646 |
39 | REPORT 양식 맞추기 | 운영자 | 2002.09.18 | 31359 |
» | 1:1 JOIN / 1:M JOIN | 운영자 | 2002.09.18 | 3000 |
37 | TUNING-01 | 운영자 | 2002.09.18 | 2739 |
36 | 소계와 합계 | 운영자 | 2002.09.18 | 3489 |
35 | 중복DATA 찾아내기 | 운영자 | 2002.09.17 | 2817 |
34 | GROUP별 DATA 분류 | 운영자 | 2002.09.17 | 2982 |
33 | PARAMETER값에 따라 변경이 일어나는 문장 | 운영자 | 2002.09.17 | 15808 |
32 | SELF JOIN | 운영자 | 2002.09.17 | 3408 |
31 | Outer Join | 운영자 | 2002.09.17 | 2918 |
30 | HINTS (출처-Oracle8.0 Tuning Guide) | 운영자 | 2002.09.17 | 2735 |
29 | 단일행 문자 함수 | 운영자 | 2002.09.17 | 2977 |
28 | 단일행 수치 함수 | 운영자 | 2002.09.17 | 2869 |
27 | NOT IN 의 함정 | 운영자 | 2002.09.17 | 2713 |