또 SQL질문입니다...ㅠㅠ 0 13 2,004

by 잼띵 [2013.01.25 14:16:46]


select co140c.ITMNM, IB010d.ITM, ib010d.qty, ib010d.amt, ib030s.iqty, ib030s.iamt,ib010d.qty - ib030s.iqty as sqty, ib010d.amt - ib030s.iamt as samt
from ib010m, ib010d, ib030s, co140c
where ib010m.ino = ib010d.ino
and co140c.itm = ib010d.itm
and ib010m.iodt between to_date(:as_yymm||01,'yyyymmdd')
and to_date(:as_yymm||TO_CHAR(LAST_DAY(TO_DATE(:as_yymm, 'yyyymm')), 'dd'),'yyyymmdd')
and ib030s.ym = :as_yymm
이런 로직이있는데 돌리면 값이안나옵니다.. 이유는 200703을 넣엇을시 ib010m.iodt에는 200703값이있지만
ib030s,ym에는 없기때문입니다
근데 sqty와 samt를 구하기 위해선 값이 없으면 0으로 출력되서 -산술식을 행하여야하는데 그게안됩니다
제생각에는 아우터조인을해서 값이없더라도 조회를해야하는데 잘안되네요

제가 질문하는거도 저두 이글을 보고이해하실지 모르겠네요... 쌩 초보라서요 제가...
원격가능하시면 도움좀 부탁드립니다 ㅜㅜ 원격으론 설명이 좀더 편할거같아요
by 마농 [2013.01.25 14:46:19]
-- 알려드린 조인조건 하나는 아예 빼먹으셨네요. 잘 확인하고 적용하세요.
-- iodt 는 date 타입이 맞나요? date 타입의 경우 Between 사용시 유의하셔야 합니다.
-- 날짜만 저장된 경우엔 아래와 같이 해도 문제 없지만
-- 시분초까지 저장된 경우엔 아래와 같이 하면 마지막날 자료는 누락되게 됩니다.
-- 날짜함수사용이 군더더기가 많네요.
SELECT co140c.itmnm
     , ib010d.itm
     , ib010d.qty
     , ib010d.amt
     , ib030s.iqty
     , ib030s.iamt
     , ib010d.qty - NVL(ib030s.iqty, 0) AS sqty
     , ib010d.amt - NVL(ib030s.iamt, 0) AS samt
  FROM ib010m
     , ib010d
     , ib030s
     , co140c
 WHERE ib010m.ino = ib010d.ino
   AND co140c.itm = ib010d.itm
   AND ib010m.iodt BETWEEN TO_DATE(:as_yymm, 'yyyymm')
                       AND LAST_DAY(TO_DATE(:as_yymm, 'yyyymm'))
   AND ib030s.itm(+) = ib010d.itm
   AND ib030s.ym(+) = :as_yymm
;

by 잼띵 [2013.01.25 14:56:54]

아 마농님 대단하세요... 제가 빼먹은이유는 이거저거하다보니까 실수로 빠진것 같네요...
(+)의 의미는 무엇인가요?ㅎㅎ

by 잼띵 [2013.01.25 15:02:40]

아우터조인이엿구나... 마농님이 해결해주신 로직보고 SQL많이공부할게요!

by 마농 [2013.01.25 15:02:57]

아우터 조인


by 마농 [2013.01.25 15:04:17]

iodt 컬럼에 대한 제 궁금증을 풀어주세요.
date ? varchar2 ?
저장되는 데이터의 형태는? 날짜만? 시분초까지?


by 잼띵 [2013.01.25 15:15:26]

아 iodt는 varchar2타입이고 yyyymmdd까지나오고
ym도 varchar2인데 yyyymm까지만나와잇습니다

by 마농 [2013.01.25 15:24:36]

그럼 조건절 수정해야 합니다.
문자컬럼엔 문자조건을 날짜컬럼엔 날짜조건을 주셔야죠.
기존에 했던 조건은 문자컬럼에 날짜조건을 준 경우로
이 경우 문자가 날짜로 자동형변환합니다.
이때 에러발생할 가능성이 농후하구요.
인덱스가 있어도 인덱스를 못탑니다.
AND ib010m.iodt BETWEEN :as_yymm || '01' AND :as_yymm || '31'


by 잼띵 [2013.01.25 15:28:19]

질문이있는데요 제가 라스트데이를 사용한이유가 2월같은경우나 31일이 안되는경우는 31을쓰면
에러가뜨던데 마농님이 적어주신 로직에서는 에러가 생기질 않는데 이유가 있나요?
varchar2타입이라 그런건가요?

by 마농 [2013.01.25 15:38:33]

문자열 비교식이라서 그렇습니다.
날짜 비교식이라면 에러나겠지요.
문자열인 경우엔 LIKE 검색도 가능합니다.
AND ib010m.iodt LIKE :as_yymm || '%'

날짜, 숫자, 문자 등 데이터 타입에 따라서 쿼리도 다르게 작성되어야 합니다.
이를 간과하는 개발자들이 너무나 많습니다.
단순한 차이이지만 엄청난 성능저하나 오류발생등 재앙이 될 수도 있습니다.


by 잼띵 [2013.01.25 15:42:08]

와 진짜 너무궁금해서 미칠뻔햇는데 감사합니다 ㅎㅎ 문자는 그럼 31로하면
알아서 28일까지만 계산한다는거네요 2월로치면?
그럼
AND ib010m.iodt BETWEEN:as_yymm ||'01' AND :as_yymm ||'31' 이로직대신
AND ib010m.iodt LIKE :as_yymm || '%' 이 로직을 넣어도 무방하다는 말씀이신거죠?
지금현재 쿼리에선

by 마농 [2013.01.25 15:59:59]

인공지능이라서 알아서 28일까지만 계산하는게 아니죠.
'28' 이 '31' 보다 작기 때문에 조건에 맞아서 나오는 것 뿐이죠.
만약 '0231' 이나 '0230' 등의 오류자료가 들어 있다면 이자료도 함께 나오겠지요.
다만 '0299' 등의 오류자료가 있다면? 이는 안나오겠지요.
LIKE 조건을 준다면 이자료도 나올거구요.
그냥 '31' 을 붙여준것은 편의상 그렇게 한것이고(28, 29, 30, 21 조건에 따라 나누기 귀찮아서)
또한, 오류자료가 없다는 묵시적인 가정하에 그렇게 한것입니다. 문자열의 특성까지 고려해서.

LIKE 로 해도 무방하구요.
다만 경우에 따라서 LIKE 가 BETWEEN 보다 늦는 경우가 발생할수도 있습니다.
"경우에 따라서"라는 전제조건 달았습니다.
"경우에 따라서"를 강조하는 것은 이런 전제조건을 앞에 달아도 대부분이 뒤에만 보고 뒤에만 암기식으로 외워버립니다.
그리고는 "LIKE 가 BETWEEN 보다 항상 늦다더라" 하고 공식화 시켜버리는 경우를 종종 체험해서...

결론은 성능상으론 거의 차이가 없습니다만.
경우에 따라서 LIKE 가 BETWEEN 보다 늦는 경우도 있으니
왠만하면 BETWEEN 을 사용하시는 것이 좋습니다.


by 신이만든짝퉁 [2013.01.25 16:06:01]
어휴~~ 저도 배우고 갑니다. ^^

by 잼띵 [2013.01.25 16:07:12]

아 정말 사소한거에도 여러가지 기능차이가 발생하네요 ㅎㅎ
감사합니다 좋은 좋언 잘들었습니다 ㅎㅎ
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입