1분단위의 데이터가 DB에 저장 되어있습니다. 이것을 3분단위로 가공을 해서 Select 하는데
기본 룰은 이렇습니다.
이름과 날짜는 그룹화 되어야하고
시간 => 3분간격의 마지막 시간
시 => 3분간격의 시 열의 첫번째 값
고 => 3분간격의 고 열의 가장 높은 값
저 => 3분간격의 저 열의 가장 낮은 값
종 => 3분간격의 종 열의 마지막 값
양 => 3분간의 양 열의 합
다만 1분단위의 데이터는 중간에 비어 있을 수 도있으며
비어있을 시 가공된 결과는
한행이라도 존재 => 존재하는 데이터 안에서 가공이 이루어집니다. (시간은 3분간격에 맞춰서 가공)
3분간격의 3행이 모두 비어있음 => 데이터 가공 없음 (시간도 비게 가공)
이렇게 가공이 되어야합니다.
이렇게 가공하는것이 가능한가요?
너무 복잡해서 질문드립니다.
DB는 오라클인지요? 허접하지만 시간을 문자열로 가정하고 SQL문을 짜봤습니다. 더 나은 방법이 있을것도 같은데.. 잘못된 부분이 있으면 지적 부탁드려요.
with t as ( select '2020-07-01' dat, 'A' nm, '0901' tim, 100 n1, 105 n2, 90 n3, 100 n4, 5500 n5 from dual union all select '2020-07-01', 'A', '0902', 100, 100, 95, 95, 1000 from dual union all select '2020-07-01', 'A', '0903', 95, 110, 95, 105, 600 from dual union all select '2020-07-01', 'A', '0904', 105, 120, 100, 110, 20 from dual union all select '2020-07-01', 'A', '0905', 110, 125, 100, 125, 800 from dual union all select '2020-07-01', 'A', '0906', 125, 125, 100, 115, 300 from dual union all select '2020-07-01', 'A', '0907', 115, 130, 110, 110, 750 from dual union all select '2020-07-01', 'A', '0908', 110, 130, 100, 125, 2000 from dual union all select '2020-07-01', 'A', '0909', 125, 125, 105, 105, 300 from dual union all select '2020-07-01', 'A', '0910', 105, 105, 95, 95, 150 from dual union all select '2020-07-01', 'B', '0901', 100, 105, 95, 100, 5000 from dual union all select '2020-07-01', 'B', '0902', 100, 100, 95, 95, 1000 from dual union all select '2020-07-01', 'B', '0903', 95, 115, 95, 105, 600 from dual union all select '2020-07-01', 'B', '0908', 110, 130, 100, 125, 2000 from dual union all select '2020-07-01', 'B', '0909', 125, 125, 105, 105, 300 from dual union all select '2020-07-01', 'B', '0910', 105, 105, 90, 95, 150 from dual ) select * from (select dat, nm, max(tim) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v1, first_value(n1) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3) order by tim) v2, max(n2) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v3, min(n3) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v4, last_value(n4) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v5, sum(n5) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v6, row_number() over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3) order by tim) rn from t) t1 where rn = 1
답변 감사드립니다. 우선 DB는 오라클이고
답변주신 내용을 확인 해 보았는데, 3, 6, 9 분까진 정확히 의도 된 대로 가공이 되었지만
10분부터 문제가 생깁니다.
DAT | NM | V1 | V2 | V3 | V4 | V5 | V6 | RN |
2020-08-03 0:00 | NAME | 903 | 57800 | 57900 | 57700 | 57800 | 1038757 | 1 |
2020-08-03 0:00 | NAME | 906 | 57800 | 57800 | 57300 | 57500 | 935380 | 1 |
2020-08-03 0:00 | NAME | 909 | 57500 | 57700 | 57300 | 57500 | 516849 | 1 |
2020-08-03 0:00 | NAME | 910 | 57400 | 57500 | 57400 | 57400 | 53786 | 1 |
2020-08-03 0:00 | NAME | 913 | 57400 | 57500 | 57300 | 57500 | 348614 | 1 |
2020-08-03 0:00 | NAME | 916 | 57400 | 57500 | 57300 | 57300 | 317624 | 1 |
2020-08-03 0:00 | NAME | 919 | 57300 | 57500 | 57300 | 57300 | 259009 | 1 |
2020-08-03 0:00 | NAME | 920 | 57300 | 57500 | 57300 | 57400 | 95908 | 1 |
2020-08-03 0:00 | NAME | 923 | 57400 | 57500 | 57300 | 57400 | 224544 | 1 |
2020-08-03 0:00 | NAME | 926 | 57400 | 57500 | 57300 | 57400 | 251719 | 1 |
2020-08-03 0:00 | NAME | 929 | 57500 | 57500 | 57400 | 57500 | 99389 | 1 |
2020-08-03 0:00 | NAME | 930 | 57400 | 57500 | 57400 | 57400 | 23052 | 1 |
3, 6, 9, 12, 15, 18, 21, 24 이런식으로 가야하는데 위의 표처럼 3,6,9 만 맞춰 버리네요 ㅜㅜ
답변을 통해서 partytion by 에 컬럼명 말고 뒤에 시간을 잘라서 붙이는 방법을 배웠습니다만
제가 아직 스스로 힌트를 통해서 정답까진 도달 하지 못하겠네요.
가능하시다면 조언을 좀더 부탁드립니다.
원글에 샘플 데이터를 올려봅니다.
헉 자리수가 세자리라 그런것 같습니다.
제 쿼리에서는 자리수로 분기하면 어떨까 싶네요. 아니면 그냥 시간값을 3으로 나누어도 될듯하고..?
select * from (select dat, nm, max(tim) over (partition by dat, nm, substr(tim,1,2), case when length(tim)=4 then ceil(substr(tim,3,2)/3) when length(tim)=3 then ceil(substr(tim,2,2)/3) end) v1, first_value(n1) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3) order by tim) v2, max(n2) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v3, min(n3) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v4, last_value(n4) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v5, sum(n5) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v6, row_number() over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3) order by tim) rn from t) t1 where rn = 1 select * from (select dat, nm, max(tim) over (partition by dat, nm, ceil(tim/3)) v1, first_value(n1) over (partition by dat, nm, ceil(tim/3) order by tim) v2, max(n2) over (partition by dat, nm, ceil(tim/3)) v3, min(n3) over (partition by dat, nm, ceil(tim/3)) v4, last_value(n4) over (partition by dat, nm, ceil(tim/3)) v5, sum(n5) over (partition by dat, nm, ceil(tim/3)) v6, row_number() over (partition by dat, nm, ceil(tim/3) order by tim) rn from t) t1 where rn = 1
아이고 제가 질문을 잘못이해했었군요.. 표시가 3분단위로 되어야하는데..
조잡하긴 하지만 아래처럼 바꾸면 될까요?
with t as ( select '2020-07-01' dat, 'A' nm, '0901' tim, 100 n1, 105 n2, 90 n3, 100 n4, 5500 n5 from dual union all select '2020-07-01', 'A', '0902', 100, 100, 95, 95, 1000 from dual union all select '2020-07-01', 'A', '0903', 95, 110, 95, 105, 600 from dual union all select '2020-07-01', 'A', '0904', 105, 120, 100, 110, 20 from dual union all select '2020-07-01', 'A', '0905', 110, 125, 100, 125, 800 from dual union all select '2020-07-01', 'A', '0906', 125, 125, 100, 115, 300 from dual union all select '2020-07-01', 'A', '0907', 115, 130, 110, 110, 750 from dual union all select '2020-07-01', 'A', '0908', 110, 130, 100, 125, 2000 from dual union all select '2020-07-01', 'A', '0909', 125, 125, 105, 105, 300 from dual union all select '2020-07-01', 'A', '0910', 105, 105, 95, 95, 150 from dual union all select '2020-07-01', 'B', '0901', 100, 105, 95, 100, 5000 from dual union all select '2020-07-01', 'B', '0902', 100, 100, 95, 95, 1000 from dual union all select '2020-07-01', 'B', '0903', 95, 115, 95, 105, 600 from dual union all select '2020-07-01', 'B', '0908', 110, 130, 100, 125, 2000 from dual union all select '2020-07-01', 'B', '0909', 125, 125, 105, 105, 300 from dual union all select '2020-07-01', 'B', '0910', 105, 105, 90, 95, 150 from dual ) select dat, nm, case when mod(substr(v1,3,2),3) = 0 then v1 else substr(v1,1,2) || ceil(substr(v1,3,2)/3)*3 end v1, v2, v3, v4, v5, v6 from (select dat, nm, max(tim) over (partition by dat, nm, substr(tim,1,2), case when length(tim)=4 then ceil(substr(tim,3,2)/3) when length(tim)=3 then ceil(substr(tim,2,2)/3) end) v1, first_value(n1) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3) order by tim) v2, max(n2) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v3, min(n3) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v4, last_value(n4) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v5, sum(n5) over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3)) v6, row_number() over (partition by dat, nm, substr(tim,1,2), ceil(substr(tim,3,2)/3) order by tim) rn from t) t1 where rn = 1
WITH t AS ( SELECT '2020-07-01' dt, 'A' nm, '0901' tm, 100 n1, 105 n2, 90 n3, 100 n4, 5500 n5 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0902', 100, 100, 95, 95, 1000 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0903', 95, 110, 95, 105, 600 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0904', 105, 120, 100, 110, 20 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0905', 110, 125, 100, 125, 800 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0906', 125, 125, 100, 115, 300 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0907', 115, 130, 110, 110, 750 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0908', 110, 130, 100, 125, 2000 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0909', 125, 125, 105, 105, 300 FROM dual UNION ALL SELECT '2020-07-01', 'A', '0910', 105, 105, 95, 95, 150 FROM dual UNION ALL SELECT '2020-07-01', 'B', '0901', 100, 105, 95, 100, 5000 FROM dual UNION ALL SELECT '2020-07-01', 'B', '0902', 100, 100, 95, 95, 1000 FROM dual UNION ALL SELECT '2020-07-01', 'B', '0903', 95, 115, 95, 105, 600 FROM dual UNION ALL SELECT '2020-07-01', 'B', '0908', 110, 130, 100, 125, 2000 FROM dual UNION ALL SELECT '2020-07-01', 'B', '0909', 125, 125, 105, 105, 300 FROM dual UNION ALL SELECT '2020-07-01', 'B', '0910', 105, 105, 90, 95, 150 FROM dual ) SELECT dt , nm , MAX(tm) tm , TO_CHAR(TO_DATE(gb * 60 * 3, 'sssss'), 'hh24mi') tm_1 , MAX(n1) KEEP(DENSE_RANK FIRST ORDER BY tm) n1 , MAX(n2) n2 , MIN(n3) n3 , MAX(n4) KEEP(DENSE_RANK LAST ORDER BY tm) n4 , SUM(n5) n5 FROM (SELECT dt, nm, tm , n1, n2, n3, n4, n5 , CEIL((TO_CHAR(TO_DATE(tm, 'hh24mi'), 'sssss') - 1) / (60*3)) gb FROM t WHERE dt = '2020-07-01' ) GROUP BY dt, nm, gb ORDER BY dt, nm, gb ;