개인사정으로 질문내용 삭제합니다 죄송합니다 0 21 1,467

by 될때까지 [SQL Query] [2013.08.05 20:26:54]


개인사정으로 질문내용 삭제합니다 죄송합니다

by 마농 [2013.08.06 08:10:58]
음.. 어렵네요... 상사분의 비위 맞추기가...
공식을 외우시는 분 같습니다.
테이블간 조인은 작은테이블을 기준으로 큰테이블을 조인하는게 좋습니다
여기가지는 공식이구요.. 그다음 응용이 부족하네요.
위 쿼리를 보면 조건절이 전혀 없습니다.
조건으로 걸러낸 후 조인하는 거라면 최대한 걸러낸뒤 그걸 기준으로 조인하는게 맞구요.
위 경우 a, b 조인시 a가 10건 b가 천만건이라 하셨는데?
그렇지 않습니다. b 는 천만건을 이미 그룹바이를 통해 11건으로 줄인 상태의 집합입니다.
즉 조인은 10 : 11 입니다. 11의 손실을 막기 위해 b를 기준으로 아우터 조인 한 것이구요.
조인에 의한 부하는 거의 없다고 보시면 됩니다. 기껏 11건 조인.
부하는 천만건을 그룹바이하는데 있죠.

- 를 + 로 바꾸라는 건 억지스런 면이 있네요.
이거 바꾸는건 일도 아니니 바꾸시면 될듯 하구요.

문제는 조인이네요.
이부분을 양보해야 하는게 맞는지? 시키는대로 하는게 맞는지? ㅎㅎㅎ
아우터 조인을 빼라고 하시면...
서브쿼리 안에서는 롤업을 하지 마세요.
조인 후 다시 한번 그룹바이 롤업하시면 되겠습니다.

by 마농 [2013.08.06 08:24:23]
혹시? 일반적인 경우는 아니지만...
a엔 코드가 10개 뿐이고 b엔 코드가 10개 이상(대량의 코드) 이라면?
그렇다면 조인을 먼저 하고 나서 그룹바이 하는게 맞구요.
일반적인 경우(코드 수는 동일하죠)에는 그룹바이 후에 조인하는게 맞습니다.

by 될때까지 [2013.08.06 09:11:36]
감사합니다 정말 많이 배워갑니다
아래 답변에 언급하신 코드가 10개뿐이고 라는 부분을 조금만 더 설명해주실 수 있으신지요?
그런 경우라면 그룹바이를 해도 건수가 줄어들지 않는건가요?

by 마농 [2013.08.06 09:21:17]
일반적인 경우 코드 테이블의 코드 수는 데이터 테이블의 코드수와 일치하거나 더 많습니다.
데이터는 대량인데 코드별로 집계하여 코드명을 조회해야 할 경우
이 경우 조인부터 하고 그룹바이 하는것 보다 그룹바이후 조인하는게 좋습니다.
그냥 좋다더라...가 아니고 왜 좋은지를 이해하셔야 합니다.
- 조인(천만번조인)후 그룹바이(천만=>10건)
- 그룹바이(천만=>10건)후 조인(10번 조인)

특수한 경우
일반 코드테이블이 아닌 조회 전용 코드테이블
코드의 종류가 총 만건정도 된다고 가정했을 때 그중 일부만(10건) 따로 떼낸 테이블이 있다고 가정하면
- 조인(천만건중 10/10000 의 데이터만 필터링 => 만건)후 그룹바이(만건=>10건)
- 그룹바이(천만=>만건)후 조인(만건 조인=>10건)
이 경우엔 천만건을 모두 읽어 그룹바이하는 비효울을 없애고
만건만 읽어 그룹바이 할 수 있습니다.
즉 데이터 건수를 줄일 수 있는 조건에 해당하지요.

by 될때까지 [2013.08.06 09:50:53]
--현재 이렇게 쿼리 작성해 본 상태입니다

select max(case when grsc = 0
      then a.rscnm else 'total' 
      end)                            as rscnm
   , max(case when grsc = 0
      then a.spec
      end)                            as spec
   , sum(b.previousyearsum)                as previousyearsum
   , sum(b.previousmonsum)                as previousmonsum
   , sum(b.mon)                         as mon
   , sum(b.monsum)                      as monsum 
   , sum(b.total)                         as totalsum
 from edu_rsc a
   , (
    select rsccd
      , grouping(rsccd)                   as grsc
      , nvl(sum(previousyear), 0)            as previousyearsum --전년누계
      , nvl(sum(previousmon), 0)            as previousmonsum --전월누계
      , nvl(sum(mon), 0)                  as mon       --당월
      , nvl(sum(previousmon + mon), 0)        as monsum     --당월누계
      , nvl(sum(previousyear + previousmon + mon), 0) as total      --총누계
     from (
       select rsccd 
          , nvl(case when whyearmon < substr(:param, 1, 4) 
               then qty * unitcost 
               end, 0)            as previousyear  -- 전년 
          , nvl(case when whyearmon > substr(:param, 1, 4) 
               and whyearmon < :param 
               then qty * unitcost 
               end, 0)            as previousmon   -- 전월 
          , nvl(case when whyearmon = :param 
               then qty * unitcost 
               end, 0)            as mon       -- 당월
        from edu_warehousing
        where whyearmon <= :param
       ) b
       group by rsccd                          --그룹핑
    )    b
 where a.rsccd = b.rsccd                            --조인
 group by rollup(b.rsccd)
 order by b.rsccd ;                              --정렬

--그런데 결과값에서 합계행의 이름(rscnm)이 total 이 아니라 흰페인트, spec은 적색으로 나오네요
--어느 부분이 잘못된건가요?

by 마농 [2013.08.06 08:36:49]
SELECT rsccd
     , NVL(CASE WHEN whyearmon < SUBSTR(:param, 1, 4)
                THEN qty * unitcost
                 END, 0)                   AS previousyear  -- 전년
     , NVL(CASE WHEN whyearmon > SUBSTR(:param, 1, 4)
                 AND whyearmon < :param
                THEN qty * unitcost
                 END, 0)                   AS previousmon   -- 전월
     , NVL(CASE WHEN whyearmon = :param
                THEN qty * unitcost
                 END, 0)                   AS mon           -- 당월

by 용근님 [2013.08.06 09:38:54]
신입이 이정도라면 아주 훌륭한거 같은데 난 신입때 모했나.. ㅎ

by 될때까지 [2013.08.06 09:51:46]
마농님 도움과 클럽내 강의자료들 아니었으면 감도 못잡고 계속 헤맸을겁니다 ㅠㅠ
정말 이런 클럽이 있다는 게 너무 감사하고 활동하시는 분들께도 너무 감사하네요

by 부쉬맨 [2013.08.06 09:43:27]
신입떼 이렇게했으나
지금은 점점떨어져가는실력..신입때가젤잘햇던거가틈..

by 될때까지 [2013.08.06 09:53:10]
db가 뭔지도 모르고 입사해서 갈 길이 머네요 ㅎㅎ
계속 노력하면 될 거라 믿고 노력중입니다

by 마농 [2013.08.06 10:01:07]
-- 안에서 Grouping 해봐야 소용 없습니다. 롤업 하는데서 그룹핑 하셔야죠.
-- rscnm과 spec을 Group By 에 포함시켜 Max 를 제거하세요.
-- 이 때 Rollup 항목을 괄호로 묶어주는것이 포인트.
SELECT CASE WHEN GROUPING(a.rsccd) = 0 THEN a.rscnm ELSE 'total' END AS rscnm
     , a.spec
  FROM a
     , (...여기서 Grouping 해봐야 아무 소용 없음...) b
 WHERE a.rsccd = b.rsccd
 GROUP BY ROLLUP((a.rsccd, a.rscnm, a.spec)) -- 괄호로 묶어줍니다.
 ORDER BY a.rsccd
;

by 될때까지 [2013.08.06 10:12:15]
하면서도 그룹핑 위치 때문에 그런건가 싶어서 이것저것 해보다가
group by a.rscnm, a.spec, rollup(a.rsccd) 하면서 헤매고 있었습니다
롤업에 대해 설명만 보고 넘어갔던터라 미처 떠올리지 못했었습니다
감사합니다

by 될때까지 [2013.08.06 11:21:12]

질문이 있습니다
롤업 항목을 괄호로 묶어주는 이유가 무엇인지요?


by 마농 [2013.08.06 11:35:18]
롤업은 롤업 항목별 소계 및 합계를 구해 줍니다.
항목이 하나이면 소계는 없죠.
항목이 둘이상이면 중간중간 소계가 나오죠.
소계가 필요 없을 때 괄호로 묶어주면 하나의 항목처럼 인식합니다.

by 될때까지 [2013.08.06 14:38:35]

아하 그렇군요 공부하면 알 수 있는 내용이었을텐데 부끄럽습니다
찬찬히 공부 계속하면서 해야겠습니다
이제 인라인뷰만 남았네요 마농님 덕분에 많이 배우고 해결했습니다 정말 감사드립니다


by 될때까지 [2013.08.06 15:28:49]
--마농님 덕분에 아래처럼 쿼리문 작성해서 해결됐습니다
select case grouping(a.rsccd) when 0 then max(a.rscnm) else 'total' end  as rscnm      --그룹핑
   , case grouping(a.rsccd) when 0 then max(a.spec) end         as spec
   , nvl(sum(b.previousyear), 0)                     as previousyearsum --전년누계
   , nvl(sum(b.previousmon), 0)                     as previousmonsum --전월누계
   , nvl(sum(b.mon), 0)                         as mon       --당월
   , sum(nvl(b.previousmon, 0) + nvl(b.mon, 0))             as monsum     --당월누계
   , sum(nvl(b.previousyear, 0) + nvl(b.previousmon, 0) + nvl(b.mon, 0)) as total      --총누계
 from edu_rsc a
   , (
    select rsccd
      , sum(case when whyearmon < substr(:param, 1, 4)
            then qty * unitcost end)              as previousyear  -- 전년
      , sum(case when whyearmon > substr(:param, 1, 4) and whyearmon < :param
            then qty * unitcost end)              as previousmon   -- 전월
      , sum(case when whyearmon = :param
            then qty * unitcost end)              as mon       -- 당월
     from edu_warehousing
    where whyearmon <= :param
    group by rsccd
    )    b
 where a.rsccd = b.rsccd
group by rollup(a.rsccd)
order by a.rsccd;
--롤업에는 a.rsccd 하나만 넣으라고해서 위처럼 수정했습니다
--union을 이용해 인라인뷰로 쿼리문 작성하는 부분은 위 쿼리문 맨 마지막 2줄 rollup과 order by절에 union을 적용하면 된다고 하는데 이해가 안됩니다
--지난번에 알려주신 
'UNION ALL 은 두개 쿼리 만들어 합치면 됩니다.
1개는 GROUP BY b.rsccd 로 SUM 하고
나머지 하나는 GROUP BY 없이 SUM 하시면 됩니다.'
라는 부분 조금만 더 자세히 설명해주실 수 있으신지요?


by 마농 [2013.08.06 16:16:33]
-- 출제자의 의도와 다를수 있습니다만... 일단 UNION 하는 방식으로
-- 1. rsccd별 합계 --
SELECT a.rsccd
     , a.rscnm
     , a.sect
     , b.previousyear                         AS previousyearsum -- 전년누계
     , b.previousmon                          AS previousmonsum  -- 전월누계
     , b.mon                                  AS mon             -- 당월
     , b.previousmon  + b.mon                 AS monsum          -- 당월누계
     , b.previousyear + b.previousmon + b.mon AS total           -- 총누계
  FROM edu_rsc a
     , (SELECT rsccd
             , NVL(SUM(CASE WHEN whyearmon < SUBSTR(:param, 1, 4)
                            THEN qty * unitcost END), 0)          AS previousyear -- 전년
             , NVL(SUM(CASE WHEN whyearmon > SUBSTR(:param, 1, 4)
                             AND whyearmon < :param
                            THEN qty * unitcost END), 0)          AS previousmon  -- 전월
             , NVL(SUM(CASE WHEN whyearmon = :param
                            THEN qty * unitcost END), 0)          AS mon          -- 당월
          FROM edu_warehousing
         WHERE whyearmon <= :param
         GROUP BY rsccd
        ) b
 WHERE a.rsccd = b.rsccd
 UNION ALL
-- 2. 전체 합계 --
SELECT Null    AS rsccd
     , 'total' AS rscnm
     , Null    AS sect
     , b.previousyear                         AS previousyearsum -- 전년누계
     , b.previousmon                          AS previousmonsum  -- 전월누계
     , b.mon                                  AS mon             -- 당월
     , b.previousmon  + b.mon                 AS monsum          -- 당월누계
     , b.previousyear + b.previousmon + b.mon AS total           -- 총누계
  FROM (SELECT NVL(SUM(CASE WHEN whyearmon < SUBSTR(:param, 1, 4)
                            THEN qty * unitcost END), 0)          AS previousyear -- 전년
             , NVL(SUM(CASE WHEN whyearmon > SUBSTR(:param, 1, 4)
                             AND whyearmon < :param
                            THEN qty * unitcost END), 0)          AS previousmon  -- 전월
             , NVL(SUM(CASE WHEN whyearmon = :param
                            THEN qty * unitcost END), 0)          AS mon          -- 당월
          FROM edu_warehousing
         WHERE whyearmon <= :param
        ) b
 ORDER BY 1
;

by 마농 [2013.08.06 16:18:53]

union all 한 후에 a와 아우터 조인하면 좀더 간단해 질텐데요.
앞서 아우터조인 쓰지 말라고 해서 좀더 복잡하게 나왔습니다.


by 될때까지 [2013.08.06 19:42:39]

시간은 오래 걸렸지만 머리 싸매고 혼자 힘으로 성공했습니다!
다 마농님 덕분이에요
감사인사드리려고 왔는데 쿼리문을 아예 작성해주셨네요 정말 감사합니다

근데 궁금한 점이 있는데, 한쪽엔 그룹 바이 하고 한쪽엔 없이 하는 이유가 뭔가요?
그렇게 하라고 알려주셨던 댓글때문에 일단 그렇게 해서 성공했는데 왜?라는 질문에 이해가 안가네요
당분간은 계속해서 시험과제가 나와서 아직 찬찬히 찾아보며 공부할 시간이 없어서 염치불구하고 질문드립니다


by 마농 [2013.08.07 08:15:21]

따로 따로 실행해서 결과 비교해 보시면 스스로 이해하실 수 있으리라 생각되네요.


by 될때까지 [2013.08.07 09:16:21]

rsccd를 출력하지 않고 보면서 고민하다가 rsccd까지 출력해놓고 보니 이해가 되네요 감사합니다

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입