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

by 될때까지 [SQL Query] [2013.08.14 15:23:18]


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


by 될때까지 [2013.08.14 15:50:19]
링크 걸어주신 퀴즈 2개 보면서 반나절을 고민했는데 계속 헤매고 있습니다
문제가 되는 부분들이라도 짚어주실 수는 없으신지요?

by 될때까지 [2013.08.14 15:53:58]

추가 질문입니다
union 을 사용해서는 해결을 했는데,
select to_char(seq) as seq
   , case max(seq) when 0 then sum(nvl(num1, 0)) else trunc(avg(nvl(num1, 0)),1) end as num1
   , case max(seq) when 0 then sum(nvl(num2, 0)) else trunc(avg(nvl(num2, 0)),1) end as num2
   , case max(seq) when 0 then sum(nvl(num3, 0)) else trunc(avg(nvl(num3, 0)),1) end as num3
 from edu_condtest
 group by seq
 union all
 select 'total'
   , case max(seq) when 0 then sum(nvl(num1, 0)) else trunc(avg(nvl(num1, 0)),1) end as num1
   , case max(seq) when 0 then sum(nvl(num2, 0)) else trunc(avg(nvl(num2, 0)),1) end as num2
   , case max(seq) when 0 then sum(nvl(num3, 0)) else trunc(avg(nvl(num3, 0)),1) end as num3
 from edu_condtest
 union all
 select 'avg'
   , case max(seq) when 0 then sum(nvl(num1, 0)) else trunc(avg(nvl(num1, 0)),1) end as num1
   , case max(seq) when 0 then sum(nvl(num2, 0)) else trunc(avg(nvl(num2, 0)),1) end as num2
   , case max(seq) when 0 then sum(nvl(num3, 0)) else trunc(avg(nvl(num3, 0)),1) end as num3
 from edu_condtest

위와 같은 쿼리로 작성하면 total 값에 평균값만 보이고,
select to_char(seq) as seq
   , case max(seq) when 0 then sum(nvl(num1, 0)) else trunc(avg(nvl(num1, 0)),1) end as num1
   , case max(seq) when 0 then sum(nvl(num2, 0)) else trunc(avg(nvl(num2, 0)),1) end as num2
   , case max(seq) when 0 then sum(nvl(num3, 0)) else trunc(avg(nvl(num3, 0)),1) end as num3
 from edu_condtest
 group by seq
 union all
 select 'total'
   , sum(nvl(num1, 0)) as num1
   , sum(nvl(num2, 0)) as num2
   , sum(nvl(num3, 0)) as num3
 from edu_condtest
 union all
 select 'avg'
   , case max(seq) when 0 then sum(nvl(num1, 0)) else trunc(avg(nvl(num1, 0)),1) end as num1
   , case max(seq) when 0 then sum(nvl(num2, 0)) else trunc(avg(nvl(num2, 0)),1) end as num2
   , case max(seq) when 0 then sum(nvl(num3, 0)) else trunc(avg(nvl(num3, 0)),1) end as num3
 from edu_condtest

위처럼 바꿔주면 정상적으로 나오네요 왜 이런걸까요?

by 마농 [2013.08.14 16:04:53]
-- Case 나 Group By 가 필요 없어 보입니다.
-- NVL 은 컬럼에 직접 하지 말고 집계후 한번만 합니다.
SELECT TO_CHAR(seq) AS seq
     , NVL(num1, 0) num1
     , NVL(num2, 0) num2
     , NVL(num3, 0) num3
  FROM edu_condtest
 UNION ALL
SELECT 'total'
     , NVL(SUM(num1), 0) num1
     , NVL(SUM(num2), 0) num2
     , NVL(SUM(num3), 0) num3
  FROM edu_condtest
 UNION ALL
SELECT 'avg'
     , NVL(TRUNC(AVG(num1), 1), 0) num1
     , NVL(TRUNC(AVG(num2), 1), 0) num2
     , NVL(TRUNC(AVG(num3), 1), 0) num3
  FROM edu_condtest
;

by 될때까지 [2013.08.14 16:16:18]

감사합니다
nvl은 컬럼에 직접 한 이유가 null도 처리를 해야해서인데,
(작성해주신 쿼리문으로 num1 컬럼의 평균값 구했을 때 /8이 아니라 null 이 빠진 /7이되서 평균값이 다르게 나옵니다)
이런 경우에는 nvl을 컬럼에 직접 해줘도 되지 않나요?

일단 아까 작성한 union 쿼리로 검수 받았는데 컬럼으로 합계와 평균을 구하는 것이 아니라 row로 구하라고 하네요 헛다리 짚고 반나절을 다른 쿼리를 짯습니다.. ㅠㅠ


by 마농 [2013.08.14 16:34:41]

평균의 의미가 무었인지에 따라 다르겠지요.
말씀하신 의미의 평균이라면 NVL 을 먼저 하는게 맞습니다.


컬럼으로 합계와 평균을 구하는 것이 아니라 row로 구하라고 하네요?
컬럼과 로우를 반대로 얘기하는듯...
Unino 이 Row 로 구하는 거죠.
Column 으로 구하는 거는 다음과 같이.
, NVL(num1, 0) + NVL(num2, 0) + NVL(num3, 0) AS tot
, (NVL(num1, 0) + NVL(num2, 0) + NVL(num3, 0)) / 3 AS avg


by 될때까지 [2013.08.14 16:45:45]
생초보 가르치시느라 힘드실텐데 너무 감사드립니다
평균 구하는 부분에 약간의 제약이 있어서
, trunc((nvl(num1, 0) + nvl(num2, 0) + nvl(num3, 0)) / 3, 1) as avg
로 해결했습니다

by 마농 [2013.08.14 15:56:18]
-- 설명하고자 하면 너무 길어질 것 같고...
-- 그냥 다음 쿼리 실행해서 결과 분석해 보세요.
-- Rollup 의 동작 원리를 이해하셔야 합니다.(설명은 이미 링크에)
SELECT seq
     , GROUPING(1) g1
     , GROUPING(seq) g2
     , GROUPING_ID(1, seq) g3
     , SUM(num1) sum_1
     , AVG(num1) avg_1
  FROM test a
 GROUP BY ROLLUP(1, seq)
 ORDER BY a.seq, GROUPING(1)
;

by 될때까지 [2013.08.14 15:59:35]
감사합니다 이해될 때까지 분석해봐야겠네요...

by 될때까지 [2013.08.16 08:45:30]

, trunc((nvl(num1, 0) + nvl(num2, 0) + nvl(num3, 0)) / 3, 1) as avg
위처럼 평균을 구했는데, nvl 연산시 예외처리(zero)에 대한 문제로 반려되어 광복절에 집에서 하루종일 검색하며 공부해보았는데 이해가 안되서 질문합니다 평균을 구할 때 나눗셈 연산 시 0으로 나누면 0이 되기 때문에 nvl 예외처리를 해야 한다고 하는데(해당 데이터로는 문제가 없지만 다른 값이 들어오면 문제가 생길 수도 있다고 합니다), 제 짧은 생각으로는 아무리 봐도 위의 문장에서 다른 어떤 수치의 데이터가 들어와도 문제가 생길 이유를 발견하지 못하겠습니다... 도움 좀 부탁드립니다 ㅠㅠ
ps. 마농님께서 중간에 답변해주신 쿼리의 평균 구하는 부분(nvl을 쓰지 않은)처럼 해야 되는 것 같은데 column으로 구하는 경우에 avg가 사용이안되는 것 같아 해결이 안되고 있습니다

by 마농 [2013.08.16 09:05:47]
전체수인 3 으로 나누는게 아닌 모양이네요.
데이터가 있는것만 평균내야 하는거군요.
데이터가 있는 갯수를 구해서 나눠주면 되구요.
3개 값이 양수만 있다고 가정하고 풀이했습니다.(0 이나 마이너스 없음)
데이터가 없는 경우는 결과가 널이 나오게 됩니다.
0 이 나오길 원하신다면 최종 NVL 하시면 됩니다.
TRUNC(
(NVL(num1, 0) + NVL(num2, 0) + NVL(num3, 0))
/ LENGTH(SIGN(num1)||SIGN(num2)||SIGN(num3))
, 1)

by 될때까지 [2013.08.16 09:27:28]
처음보는 함수들이 나왔네요 공부 좀 하고 사용해야겠습니다 감사드립니다

by 될때까지 [2013.08.16 09:39:47]
num3에 -값이 하나 있습니다
이런 경우는 어떻게 해결해야 하나요?

그리고 sign에 대해 알아보니 어떻게 사용되는지는 알겠는데,
테이블에 데이터가 null 20 -1 인 행이 있습니다
알려주신 함수를 사용하면 합계는 19, 평균은 6.3으로 나오는데
제가 이해한 대로라면 19를 1로 나누어서 19가 나와야 하는 것이 아닌가요?
0, 1, -1 이니까요
그런데 왜 19를 3으로 나눈 값이 나오는건지 궁금합니다
(실제 구해야 하는 값은 19를 2로 나눈 값이 나와야겠지만요)

by 마농 [2013.08.16 09:52:20]
제가 드린 답변은 앞서 몇가지 가정을 하고 드린 답변입니다.
가정이 틀렸다면 답변도 틀린 것입니다. 틀린 답변에 대한 추가 질문은 필요 없어 보입니다.
새로운 가정하에 새로운 답변을 요구하는 질문을 하셔야죠.
추가 질문도 좀 이상하네요.
합계는 19, 평균은 6.3으로 나오는데 ==> 3으로 나누어서 그렇습니다.('1-1' 의 길이가 3이므로)
19를 1로 나누어서 19가 나와야 하는 것이 아닌가요? ==> 왜 1이 나온다고 생각하죠?
전체 수식을 이해하려 하지 마시고.. 수식을 단계별로 쪼개어 값을 확인하셔야 합니다.

by 될때까지 [2013.08.16 10:09:09]
항상 명확하게 이해되는 설명 감사드립니다 제가 length에 대해 잘못 이해를 하고 있었네요
1-1의 연산 결과가 아니라 길이를 봐야 하는 것을 착각하고 있었습니다
그렇다면 -값이 존재한다는 새로운 가정하에 아예 다른 방식으로 생각해봐야하겠군요

by 마농 [2013.08.16 10:06:06]
-- Null 을 제외한 3값의 평균 --
Null 이 아닌 값은 모두 평균에 포함됩니다.(음수나 0 값도 포함)
TRUNC(
(NVL(num1, 0) + NVL(num2, 0) + NVL(num3, 0))
/ NULLIF(NVL2(num1, 1, 0) + NVL2(num2, 1, 0) + NVL2(num3, 1, 0), 0)
, 1)

-- 함수 소개 --
SIGN(v) : v가 양수이면 1, 음수이면 -1, 0이면 0, (주의 : 널이면 널)
v1 || v2 : 문자열을 연결하는 연산자
LENGTH(v) : 문자열 v 의 크기, 주의(널일경우 0이 아닌 널을 반환)
NVL2(v, v1, v2) : v가 널이 아니면 v1, v가 널이면 v2
NULLIF(v, v1) : v가 v1과 같으면 널, 그렇지 않으면 v 그대로
http://oracleclub.com/oracle/sql

by 될때까지 [2013.08.16 10:14:52]
함수소개까지.. 정말 감사드립니다 질문을 하면 할 수록 쿼리에 대한 배움뿐만 아니라 기초의 중요성도 크게 느끼고 배워갑니다 남는 시간에 보다 더 열심히 기초공부를 해야겠습니다...

by 마농 [2013.08.16 12:06:42]

글쎄요...
왜? sum 을 사용해야 한다고 생각하는지 모르겠네요.

NULLIF(v, v1) : v가 v1과 같으면 널, 그렇지 않으면 v 그대로
NullIf 사용 안하고 같은 기능 구현하기
CASE WHEN v = v1 THEN null ELSE v END
DECODE(v, v1, null, v)

실전에 적용하기
(NVL(num1, 0) + NVL(num2, 0) + NVL(num3, 0))
/ DECODE
( NVL2(num1, 1, 0) + NVL2(num2, 1, 0) + NVL2(num3, 1, 0), 0, Null
, NVL2(num1, 1, 0) + NVL2(num2, 1, 0) + NVL2(num3, 1, 0)
)

다른 방법으로 접근하기
CASE
WHEN num1 IS NULL AND num2 IS NULL AND num3 IS NULL
THEN Null
ELSE (NVL(num1, 0) + NVL(num2, 0) + NVL(num3, 0))
/ (NVL2(num1, 1, 0) + NVL2(num2, 1, 0) + NVL2(num3, 1, 0))
END

방법은 무궁무진합니다.
정해진 답이 있다 해도...
비효율이 있어서 그것을 바로 잡아주는것은 몰라도
비효율이 없는데도 정해진 답과 다르다는 이유로 트집을 잡는다면 쫌....


by 될때까지 [2013.08.16 12:21:54]
아 case 를 적용할 수도 있었군요
답변을 보는 순간 아참 이렇게 할 수도 있었구나 싶네요
그래도 이렇게 반려되면서 많은 것들 배우고 느낍니다 제 수준에는 효율보다는 여러가지 방법을 직접 활용해보는 것이 중요하기 때문에 그런 것 같네요
최근 너무 자주 도움을 청하는 것 같아 부끄럽습니다
필요할 때에 여러가지 방법들을 떠올리려면 계속 해보면서 제 것으로 만드는 방법 밖엔 없겠네요
몇번을 감사하다는 인사를 드려도 부족한 것만 같습니다
식사 맛있게 하시고 오세요~
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입