안녕하세요. 구루비에서 많은 도움을 얻고 있습니다. 감사드립니다.
M_CUS(고객) 와 T_ORD(주문) 테이블은 1:N 관계입니다.
2017년 3월에 주문 이력이 있는 고객 정보를 얻는 것이 목표입니다.
<교재 모범 쿼리>
SELECT T1.CUS_ID ,T1.CUS_NM
,(CASE WHEN
EXISTS(
SELECT *
FROM T_ORD A
WHERE A.CUS_ID = T1.CUS_ID
AND A.ORD_DT >= TO_DATE('20170301','YYYYMMDD')
AND A.ORD_DT < TO_DATE('20170401','YYYYMMDD')
)
THEN 'Y'
ELSE 'N' END) ORD_YN_03
FROM M_CUS T1
ORDER BY 1;
<임의 변경>
SELECT T1.CUS_ID ,T1.CUS_NM
, (
SELECT NVL( MAX('Y'),'N')
FROM T_ORD A
WHERE A.CUS_ID = T1.CUS_ID
AND A.ORD_DT >= TO_DATE('20170301','YYYYMMDD')
AND A.ORD_DT < TO_DATE('20170401','YYYYMMDD')
-- AND ROWNUM <= 1 -- 해당 조건을 붙이는 것이 맞으나
-- 실수로 주석처리 하였더니 위와 다른 결과가 나옴
) "ORD_YN_03"
FROM M_CUS T1
ORDER BY 1;
ROWNUM 라인을 주석을 풀면 원하는 결과가 나오지만,
ROWNUM 라인 주석 해제시 원하는 결과가 나오지 않습니다. (결과가 달라짐)
제가 3시간 이상 생각해 보았을 때는 도저히 차이를 모르겠는데 어떤 이유인지 힌트라도 부탁드려도 될까요...
감사합니다.
WITH m_cus AS
(
SELECT 1 cus_id, 'A' cus_nm FROM dual
UNION ALL SELECT 2, 'B' FROM dual
UNION ALL SELECT 3, 'C' FROM dual
UNION ALL SELECT 4, 'D' FROM dual
)
, t_ord AS
(
SELECT 1 cus_id, DATE '2017-03-01' ord_dt FROM dual
UNION ALL SELECT 1, DATE '2017-03-02' FROM dual
UNION ALL SELECT 1, DATE '2017-03-03' FROM dual
UNION ALL SELECT 2, DATE '2017-03-04' FROM dual
UNION ALL SELECT 3, DATE '2017-04-01' FROM dual
)
SELECT t1.cus_id
, t1.cus_nm
, CASE WHEN EXISTS (SELECT *
FROM t_ord a
WHERE a.cus_id = t1.cus_id
AND a.ord_dt >= TO_DATE('20170301', 'yyyymmdd')
AND a.ord_dt < TO_DATE('20170401', 'yyyymmdd')
)
THEN 'Y' ELSE 'N' END ord_yn_01
, (SELECT NVL(MAX('Y'), 'N')
FROM t_ord a
WHERE a.cus_id = t1.cus_id
AND a.ord_dt >= TO_DATE('20170301', 'yyyymmdd')
AND a.ord_dt < TO_DATE('20170401', 'yyyymmdd')
) ord_yn_02
, (SELECT NVL(MAX('Y'), 'N')
FROM t_ord a
WHERE a.cus_id = t1.cus_id
AND a.ord_dt >= TO_DATE('20170301', 'yyyymmdd')
AND a.ord_dt < TO_DATE('20170401', 'yyyymmdd')
AND ROWNUM <= 1
) ord_yn_03
FROM m_cus t1
ORDER BY 1
;
-- 결과 동일함 --
1 A Y Y Y
2 B Y Y Y
3 C N N N
4 D N N N
n/a
테이블 생성헤서 테스트 해봤는데 결과 동일합니다. 정상.
마농님. 테스트해본 결과 버그인 것 같습니다.
두 환경 12.2(no patch), 18c(no patch) 에서 테스트했을 때는 똑같이 "비정상.jpg" 처럼 나왔는데
psu가 적용된 실제 서버에서 테스트해보니 올바른 결과가 나오네요. "정상.jpg" 처럼 올바른 결과가 나오네요
- 12c psu 적용 / 19c psu 적용
메인글의 첨부파일에 "비정상.jpg"로 업로드 하였습니다.
위 스크립트로 저도 새로 만들어서 구조가 다를 가능성도 없는데 신기하네요...
AND ROWNUM <= 1
실행계획에 따라 다른 1row를 가져올 수 있는데 order by 로 명시적 조건을 부여하는것이 어떠실까요?
결국 SELECT 절에서는 'Y' 를 조회하므로
- 어떤 행을 가져오든 결과는 'Y' 가 됩니다.
- 어떤 행도 못 가져오면 결과는 'N' 이 됩니다.
즉, ROWNUM 에 의해 가져오는 행이 달라진다고 결과가 달라지지는 않습니다.
즉, 이 문제는 존재여부를 체크하는 쿼리로
어떤 행을 가져오는지가 중요한게 아니라 행이 존재하는지가 중요합니다.
존재여부만 판명하므로 1행만 가져오는게 유리하므로 ROWNUM 조건을 주는게 맞긴한데.
ROWNUM 안준다고 해서 결과가 달라져서는 안되는데, 결과가 달라지는 버그가 있었던 것 같습니다.