학생 수 지역 |
2018년 (1,2차) |
2019년 (3,4차) |
2020년 (5,6차) |
2021년 (7,8차) |
2022년 (9,10차) |
2023년 (11,12차) |
2024년 (13차) |
합계 |
|||||
중학교 |
중학교 |
중학교 |
초 |
중 |
초 |
중 |
초 |
중 |
초 |
중 |
초 |
중 |
|
서 울 |
2 |
5 |
2 |
1 |
5 |
- |
1 |
2 |
1 |
1 |
1 |
4 |
17 |
부 산 |
- |
- |
- |
- |
- |
- |
- |
- |
1 |
- |
- |
0 |
1 |
대 구 |
- |
- |
- |
- |
- |
- |
- |
- |
1 |
- |
1 |
0 |
2 |
인 천 |
- |
- |
- |
- |
1 |
- |
- |
- |
- |
- |
- |
0 |
1 |
광 주 |
- |
- |
- |
- |
- |
- |
- |
1 |
- |
- |
- |
1 |
0 |
대 전 |
- |
- |
2 |
1 |
4 |
- |
2 |
- |
4 |
- |
2 |
1 |
14 |
위와 같은 형태의(위에는 예시) 통계를 짜야하는데 쿼리에 미숙해서 짜다가 의문이 들어서 조언을 구하기 위해 남깁니다
SELECT
'제주' ADDR_NM,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2018' AND AER_TYPE = 'M' THEN CNT END, 0)), 0) MS1,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2019' AND AER_TYPE = 'M' THEN CNT END, 0)), 0) MS2,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2020' AND AER_TYPE = 'M' THEN CNT END, 0)), 0) MS3,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2021' AND AER_TYPE = 'P' THEN CNT END, 0)), 0) AER_ES1,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2021' AND AER_TYPE = 'M' THEN CNT END, 0)), 0) AER_MS1,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2022' AND AER_TYPE = 'P' THEN CNT END, 0)), 0) AER_ES2,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2022' AND AER_TYPE = 'M' THEN CNT END, 0)), 0) AER_MS2,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2023' AND AER_TYPE = 'P' THEN CNT END, 0)), 0) AER_ES3,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2023' AND AER_TYPE = 'M' THEN CNT END, 0)), 0) AER_MS3,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2024' AND AER_TYPE = 'P' THEN CNT END, 0)), 0) AER_ES4,
NVL(SUM(NVL(CASE WHEN CREATE_YEAR = '2024' AND AER_TYPE = 'M' THEN CNT END, 0)), 0) AER_MS4,
NVL(SUM(NVL(CASE WHEN AER_TYPE = 'P' THEN CNT END, 0)), 0) "ES_TOT",
NVL(SUM(NVL(CASE WHEN AER_TYPE = 'M' THEN CNT END, 0)), 0) "MS_TOT"
FROM (
SELECT
TO_CHAR(TO_DATE(CREATE_DT, 'YYYYMMDDHH24MISS'), 'YYYY') CREATE_YEAR,
AER_ADDR_CD,
AER_TYPE,
COUNT(AER_ID) CNT
FROM KEDI_ACRDT_EDU_REQ
WHERE AER_ADDR_CD = '9290000' <--------- 이게 db에 저장되어있는 지역별 코드입니다
GROUP BY CREATE_DT, AER_ADDR_CD, AER_TYPE
)
이런식으로 지역별 통계를 union해서 하는 식으로 해보려했는데 결과는 원하는대로 나오는데 문제는
저렇게 create_year = 년도 이런식으로 하니까
추후 년도가 넘어가면 그때 저렇게 추가해주지않으면 그 년도가 정상출력이 안될거같아서 고민이됩니다.
혹시 조그만 조언이라도 해주시면 감사하겠습니다ㅜ
해결방법
2018부터 현재년도까지의 통계를 출력해야하고 반복되는 쿼리가 있어서
java에서 years라는 변수에 리스트로 담아서
SUM(CASE WHEN SUBSTR(AER_DATE, 1,4) LIKE CONCAT(REPLACE(#years[]#, '''', ''),'%') AND SCHOOL_LV = '01' THEN 1 ELSE 0 END) AS AER_ES$years[]$,
SUM(CASE WHEN SUBSTR(AER_DATE, 1,4) LIKE CONCAT(REPLACE(#years[]#, '''', ''),'%') AND SCHOOL_LV = '02' THEN 1 ELSE 0 END) AS AER_MS$years[]$,
이런식으로 iterate를 돌려서 해결하였습니다.
다만 이런식으로 하면 화면단도 동적으로 구성하여야 하니 혹여나 비슷한 문제로 고민하시는분들은 유의하여 참고가 되시길 바랍니다!
ps. AER_ES$years[]$, alias 부분은 저 방법 외엔 어떤 걸 써도 해결이 되지 않아 $$로 사용을 했는데 실질적으로 취약점 점검에는 걸리는 부분인것으로 알아서
주의하셔야합니다.
1. 복잡한 연도 구하기 개선
- 현재 : TO_CHAR(TO_DATE(create_dt, 'yyyymmddhh24miss'), 'yyyy') create_year
- 개선 : SUBSTR(create_dt, 1, 4) create_year
2. 지역별로 따로 쿼리해서 유니온 하나요?
- 지역 조건 없애고 그룹바이 지역 하면 유니온 안해도 됩니다.
- 지역명은 코드테이블 조인해서 가져오도록 하는게 좋습니다.
3. 연도 자동화
- 연도를 직접 조건으로 주지 말고
- 현재연도와의 차이를 구해 조건으로 주면 됩니다.
4. aer_id 는 널 가능한가요?
- 널이 없는 항목이라면? 굳이 COUNT(aer_id) 할 필요가 없습니다.
- 그냥 COUNT(*) 하시면 됩니다.
5. 합계 와 연도별 합계 불일치 현상 발생
- 합계에는 연도 조건이 없어 2018년 이전 값도 합산됨
- 2018~2020년은 중등만 뽑고 있는데 합계에서는 초등도 뽑고 있음
- 죄측 연도별 합계의 합산결과와 우측 합계의 값이 일치하지 않을 수 있음
- 이게 맞는지?
선배님.. 아무리 줄여도
SELECT
AER_ADDR_NM,
SUM(CASE WHEN CREATE_DT LIKE '2018%' AND AER_TYPE = 'M' THEN 1 ELSE 0 END) AS MS1,
SUM(CASE WHEN CREATE_DT LIKE '2019%' AND AER_TYPE = 'M' THEN 1 ELSE 0 END) AS MS2,
SUM(CASE WHEN CREATE_DT LIKE '2020%' AND AER_TYPE = 'M' THEN 1 ELSE 0 END) AS MS2,
SUM(CASE WHEN CREATE_DT LIKE '2021%' AND AER_TYPE = 'P' THEN 1 ELSE 0 END) AS AER_ES1,
SUM(CASE WHEN CREATE_DT LIKE '2021%' AND AER_TYPE = 'M' THEN 1 ELSE 0 END) AS AER_MS1,
SUM(CASE WHEN CREATE_DT LIKE '2022%' AND AER_TYPE = 'P' THEN 1 ELSE 0 END) AS AER_ES2,
SUM(CASE WHEN CREATE_DT LIKE '2022%' AND AER_TYPE = 'M' THEN 1 ELSE 0 END) AS AER_MS2,
SUM(CASE WHEN CREATE_DT LIKE '2023%' AND AER_TYPE = 'P' THEN 1 ELSE 0 END) AS AER_ES3,
SUM(CASE WHEN CREATE_DT LIKE '2023%' AND AER_TYPE = 'M' THEN 1 ELSE 0 END) AS AER_MS3,
SUM(CASE WHEN CREATE_DT LIKE '2024%' AND AER_TYPE = 'P' THEN 1 ELSE 0 END) AS AER_ES4,
SUM(CASE WHEN CREATE_DT LIKE '2024%' AND AER_TYPE = 'M' THEN 1 ELSE 0 END) AS AER_MS4,
(SELECT ORG_ORD FROM TCMN_ORG WHERE ORG_CD = AER_ADDR_CD) ORG_ORD
FROM 테이블명
GROUP BY AER_ADDR_NM, AER_ADDR_CD
ORDER BY ORG_ORD ASC;
이정도밖에 안떠오르는데 혹시 여기서 좀 더 감안해야할게 있을까요ㅜ
SELECT aer_addr_nm , COUNT(CASE y WHEN 6 THEN m END) ms1 , COUNT(CASE y WHEN 5 THEN m END) ms2 , COUNT(CASE y WHEN 4 THEN m END) ms3 , COUNT(CASE y WHEN 3 THEN p END) aer_es1 , COUNT(CASE y WHEN 3 THEN m END) aer_ms1 , COUNT(CASE y WHEN 2 THEN p END) aer_es2 , COUNT(CASE y WHEN 2 THEN m END) aer_ms2 , COUNT(CASE y WHEN 1 THEN p END) aer_es3 , COUNT(CASE y WHEN 1 THEN m END) aer_ms3 , COUNT(CASE y WHEN 0 THEN p END) aer_es4 , COUNT(CASE y WHEN 0 THEN m END) aer_ms4 , COUNT(p) es_tot , COUNT(m) ms_tot , COUNT(*) tot FROM (SELECT a.aer_addr_cd , a.aer_addr_nm , b.org_ord , TO_CHAT(sysdate, 'yyyy') - SUBSTR(create_dt, 1, 4) y , CASE aer_type WHEN 'P' THEN 1 END p , CASE aer_type WHEN 'M' THEN 1 END m FROM kedi_acrdt_edu_req a , tcmn_org b WHERE a.aer_addr_cd = b.org_cd ) GROUP BY org_ord, aer_addr_cd, aer_addr_nm ORDER BY org_ord ;
1. 지역명을 가져오는 방법?
- 원본 테이블에 있나요? 조인이 필요한가요?
- 혹시 tcmn_org 테이블에 지역명이 있는 것은 아닌지?
2. 합계 표시는?
- 합계에 어디까지 포함이 될지 고민이 필요합니다.
- 전체 다 포함할지? 최근 7년치만 표함할지?
- 2028~2020 사이의 m 만 포함할지? p 도 포함할지?
컬럼을 가변적으로 늘리는 것은 쿼리만으로는 안됩니다.
- 1안) 동적쿼리를 사용하는 방안
- 2안) 매년 초에 쿼리 수정하는 방안
SELECT aer_addr_nm , COUNT(CASE y WHEN 1 THEN m END) ms1 , COUNT(CASE y WHEN 2 THEN m END) ms2 , COUNT(CASE y WHEN 3 THEN m END) ms3 , COUNT(CASE y WHEN 4 THEN p END) es4 , COUNT(CASE y WHEN 4 THEN m END) ms4 , COUNT(CASE y WHEN 5 THEN p END) es5 , COUNT(CASE y WHEN 5 THEN m END) ms5 , COUNT(CASE y WHEN 6 THEN p END) es6 , COUNT(CASE y WHEN 6 THEN m END) ms6 , COUNT(CASE y WHEN 7 THEN p END) es7 , COUNT(CASE y WHEN 7 THEN m END) ms7 -- , COUNT(CASE y WHEN 8 THEN p END) es8 -- 2025년 추가 -- , COUNT(CASE y WHEN 8 THEN m END) ms8 -- 2025년 추가 -- , COUNT(CASE y WHEN 9 THEN p END) es9 -- 2026년 추가 -- , COUNT(CASE y WHEN 9 THEN m END) ms9 -- 2026년 추가 , COUNT(p) es_tot , COUNT(m) ms_tot , COUNT(*) tot FROM (SELECT a.aer_addr_cd , b.org_nm aer_addr_nm , b.org_ord , SUBSTR(create_dt, 1, 4) - 2018 + 1 y , CASE aer_type WHEN 'P' THEN 1 END p , CASE aer_type WHEN 'M' THEN 1 END m FROM kedi_acrdt_edu_req a , tcmn_org b WHERE a.aer_addr_cd = b.org_cd ) GROUP BY org_ord, aer_addr_cd, aer_addr_nm ORDER BY org_ord ;