/*
테이블 명(tname)과 기준 컬럼 명(cname)을 받아
전체 컬럼의 정보획득량(분할 전 엔트로피 - 분할 후 엔트로피)를 출력해주는 프로시저
*/
create or replace procedure ent_ttt
is
tname varchar2(100) := 'ttt';
cname varchar2(100) := 'res';
v_col varchar2(20);
v_local_cnt number(10,3);
v_local_total number(10,3);
v_total number(10,3);
--쿼리
v_stmt varchar2(1000);
--분할 전 엔트로피
v_entropy number(10,5);
v_temp number(10,5);
--분할 후 엔트로피
v_entropy2 number(10,5);
--분할 전 엔트로피 중복 계산 방지하는 변수 : column의 값 하나 당 한 번만 계산하게
v_recent_calculated_column varchar2(100) := 'isNotCalculated';
--가장 정보량이 많은 컬럼 및 정보량
v_most_col varchar2(100);
v_most_val number(10,5) := 0;
type refcursor is ref cursor; --refcursor 데이터타입 선언
emp_cv refcursor; --emp_cv라는 ref cursor 변수 선언
--column 리스트를 가져옴
cursor skin_column_cursor is
select column_name
from dba_tab_columns
where table_name = upper(tname);
begin
--가져온 column list를 이용해 각 column에 대해 sql문 실행
for i in skin_column_cursor loop
continue when i.column_name in (upper(cname));
--컬럼이 바뀔 때마다 상태 초기화
v_entropy := 0;
v_entropy2 := 0;
v_recent_calculated_column := 'isNotCalculated';
--쿼리
v_stmt := 'select ' || i.column_name || ', cnt,
sum(cnt) over(partition by ' || i.column_name || ') tot1,
sum(cnt) over() tot2
from
(
select distinct a.' || i.column_name || ' as ' || i.column_name || ',
b.' || cname || ' as ' || cname || ',
(select count(*)
from ' || tname || '
where ' || i.column_name || ' = a.' || i.column_name || '
and ' || cname || ' = b.' || cname || ') cnt
from ' || tname || ' a,
' || tname || ' b
where a.' || i.column_name || ' != 1
)
order by ' || i.column_name;
open emp_cv for v_stmt;
loop
/*
v_local_cnt : 기준컬럼/대상컬럼으로 나눈 가장 최소단위 숫자
v_local_total : 대상컬럼의 각 값의 총합
v_total : 전체 총합
*/
fetch emp_cv into v_col, v_local_cnt, v_local_total, v_total;
exit when emp_cv%notfound;
--분할 전 엔트로피 : 컬럼의 값당 1회만 계산하게
if v_recent_calculated_column != v_col then
v_recent_calculated_column := v_col;
v_temp := ((-1) * (v_local_total / v_total) * log(2,(v_local_total/v_total)));
v_entropy := v_entropy + v_temp;
end if;
--분할 후 엔트로피
if v_local_cnt/v_local_total != 0 then
v_temp := ((-1) * (v_local_total / v_total) * (v_local_cnt / v_local_total) * log(2,(v_local_cnt/v_local_total)));
v_entropy2 := v_entropy2 + v_temp;
end if;
end loop;
--결과 출력
dbms_output.put_line('[' || i.column_name || ']');
dbms_output.put_line('분할 전 엔트로피 : ' || v_entropy );
dbms_output.put_line('분할 후 엔트로피 : ' || v_entropy2);
dbms_output.put_line('정보 획득량 : ' || (v_entropy - v_entropy2) || chr(10));
if v_most_val < (v_entropy - v_entropy2) then
v_most_val := (v_entropy - v_entropy2);
v_most_col := i.column_name;
end if;
end loop;
dbms_output.put_line('최대 정보량을 지닌 컬럼 : ' || v_most_col);
dbms_output.put_line('최대 정보량 : ' || v_most_val);
end;
/