메뉴 건너뛰기

tnt_db

Oracle 중복 DATA CHECK

운영자 2002.09.17 20:20 조회 수 : 2680 추천:20

학과테이블입니다. (학과 코드와 이름입니다.)
create table major (
major_num       varchar2(10)                 --학과번호
constraint maj_maj_num_pk primary key,
major_name      varchar2(20) not null        --학과이름
);      

학생테이블입니다.(학생의 정보입니다.)
create table student (
stu_num         number(15)                               --학번
constraint stu_stu_num_pk primary key,
passwd          number(15) not null,                     --주민번호
year            number(3),                               --학년
major_num       varchar2(10)                             --학과번호
constraint stu_maj_num_fk references major(major_num),
name            varchar2(15),                            --이름
address         varchar2(30),                            --주소
phone_num       varchar2(15),                            --전화번호
e_mail          varchar2(40),                            --이메일주소
total_grade     number(3) default 21,                    --신청가능학점
cur_grade       number(3) default 0                      --현재신청학점
);
  

교수테이블입니다. (교수의 정보입니다.)
create table prof (
prof_num   number(15)                                       --교수번호
constraint prof_prof_num_pk primary key,
passwd     number(15) not null,                             --주민번호
major_num  varchar2(10)                                     --학과번호
constraint prof_prof_num_fk references major(major_num),
name       varchar2(15),                                    --이름
address    varchar2(30),                                    --주소

phone_num  varchar2(15),                                    --전화번호
e_mail     varchar2(40)                                     --이메일주소
);                                    

과목테이블입니다. (과목의 정보입니다.)

(그래서 많은 분들은 제의도와는 다르게 학번과 과목을 pk로 잡으라하시더군요.
그러면, 한사람밖에 삽입되지 않나요? 과목도 다른 사람이 먼저 신청하면,
신청을 할 수 없는 거구요...)
create table subject (
sub_num         varchar2(10) primary key,                 --과목번호
sub_name        varchar2(15) not null,                    --과목명
sub_part        number(3) ,                               --영역
time1           varchar2(5),                              --월요일
time2           varchar2(5),                              --화요일
time3           varchar2(5),                              --수요일
time4           varchar2(5),                              --목요일
time5           varchar2(5),                              --금요일
full_student    number(3) not null,                       --총인원
current_student number(3) default 0,                      --현수강신청인원
room_num        varchar2(5),                              --강의실번호
part_num        varchar2(5) not null,                     --분반
part            varchar2(10),                             --과목분류(전선)
grade           number(3),                                --학점
prof_num        number(15)                                --교수번호
constraint sub_prof_num_fk references prof(prof_num),
major_num       varchar2(10)                              --소속학과
constraint sub_maj_num_fk references major(major_num)
);                                

수강신청테이블입니다. (여기엔 수강신청을 하는 모든 학생의 과목내용이 기록됩니다.)
create table ord (
stu_num         number(15) not null,              --학번
sub_num         varchar2(10) not null,            --과목명
time1           varchar2(5),                      --월요일
time2           varchar2(5),                      --화요일
time3           varchar2(5),                      --수요일
time4           varchar2(5),                      --목요일
time5           varchar2(5),                      --금요일
ord_date        date default sysdate,             --신청일
constraint ord_stu_num_fk foreign key (stu_num)
references student(stu_num),
constraint ord_sub_num_fk foreign key (sub_num)
references subject(sub_num)
);                                
  
==그리고 스크립트  처리 부분입니다. 좀 지저분하지만 아니, 많이 지저분하지만
  이해해 주세요 ^^==
create or replace procedure ins_sub(
the_stu_num     in      number default null ,
the_passwd      in      number default null,
the_sub_num     in      varchar2 default null)
is
v_sub_rec               subject%rowtype;
v_ord_rec               ord%rowtype;
v_time1                 subject.time1%type;
v_time2                 subject.time2%type;
v_time3                 subject.time3%type;
v_time4                 subject.time4%type;
v_time5                 subject.time5%type;
v_full_student          subject.full_student%type;
v_current_student       subject.current_student%type;
v_name                  student.name%type;
v_major_name            major.major_name%type;
v_sub_part              subject.sub_part%type;
time_value              boolean default false;
cursor cu is select * from ord
where stu_num = the_stu_num
order by sub_num;
dummy BOOLEAN;      

begin

select name into v_name
from student
where stu_num = the_stu_num;


select * into v_sub_rec from subject where sub_num = the_sub_num;

select time1, time2, time3, time4, time5
       into v_time1, v_time2, v_time3, v_time4, v_time5
from subject
where sub_num = the_sub_num;
htp.htmlopen;
htp.headopen;
htp.title('1단계 수강신청');
htp.headclose;
htp.bodyopen;
htp.p('<BODY background="/ows-img/orhmbkgn.jpg" text="#000088" link="#BB0000" vl
ink="#BB0000">');
htp.centeropen;    

=*=*=*=*=*이부분입니다. 이부분을 어떻게 해결해야 될까요?
    제 의도는 기존의 수강신청테이블에 시간표가 중복되는지의 여부를 체크한다고
    작성해본 부분입니다.


/*

for i in cu loop
if ( ((substr(i.time1,1,1) <> v_time1) or (substr(i.time1,-1,1) <> v_time1) or
(substr(i.time1,1,3) <> v_time1))
and  ((substr(i.time2,1,1) <> v_time2) or (substr(i.time2,-1,1) <> v_time2) or
(substr(i.time2,1,3) <> v_time2))
and  ((substr(i.time3,1,1) <> v_time3) or (substr(i.time3,-1,1) <> v_time3) or
(substr(i.time3,1,3) <> v_time3))
and  ((substr(i.time4,1,1) <> v_time4) or (substr(i.time4,-1,1) <> v_time4) or
(substr(i.time4,1,3) <> v_time4))

and  ((substr(i.time5,1,1) <> v_time5) or (substr(i.time5,-1,1) <> v_time5) or
(substr(i.time5,1,3) <> v_time5)))
then
v_var := 100;
time_value := TRUE;
end if;
end loop;

*/

htp.header(1,'환 영 합 니 다.');
htp.p(v_name||' 학생이 신청한 과목 '||the_sub_num||' 입니다');

htp.br;
if(time_value) then
select full_student, current_student into v_full_student, v_current_student

from subject
where sub_num = the_sub_num;
if ( v_current_student <= v_full_student ) then
  --같은 과목이 검출되는지 여부를 조사하는 코드 첨가해야한다.


  v_current_student := v_current_student + 1;

  update subject
  set current_student = v_current_student
  where sub_num = the_sub_num;

   htp.br;
   htp.br;
  insert into ord(stu_num, sub_num, time1, time2, time3, time4, time5)
  values (the_stu_num, the_sub_num, v_sub_rec.time1, v_sub_rec.time2,
        v_sub_rec.time3, v_sub_rec.time4, v_sub_rec.time5);
                                                                  
  htp.p('성공적으로 신청되었습니다.');
else
htp.bold('지금 신청하신 과목은 정원을 초과합니다. 다시 신청해 주십시오.');
end if;
end if;
dummy := owa_util.tableprint('ord,subject','BORDER',owa_util.html_table,
'ord.sub_num,subject.part,subject.sub_name, ord.ord_date ',
'where ord.sub_num = subject.sub_num     and
       ord.stu_num = '''||the_stu_num||''' ',
'과목번호,구분,과목명,신청일');

htp.br;
htp.br;
htp.br;
htp.br;
--

htp.p('<TD><HR NOSHADE size="2"></TD>');
htp.br;
-- htp.formopen( 'state1' );
-- htp.formsubmit(null,'과목보기 창으로');
htp.br;
htp.br;


--
htp.p('<TD><HR NOSHADE size="2"></TD>');
htp.bold('취소할 과목이 있으면 아래 사항을 정확히 기입하시오');
htp.br;
htp.formopen( 'login_check3' );

htp.tableData( '<FONT color=blue size=3>' ||
                htf.bold( '당신의 학번은, ') ||
                '</FONT>' || htf.formtext('the_stu_num',15,15) ||
                '<FONT color=blue size=3>' ||
                htf.bold( ' ') ||
                '</FONT>');

htp.tableData( '<FONT color=blue size=3>' ||
                htf.bold( '당신의 주민번호는,  ') ||
                '</FONT>' || htf.formpassword('the_passwd',15,15) ||
                '<FONT color=blue size=3>' ||
                htf.bold( ' ') ||                      
                 '</FONT>');

htp.tableData( '<FONT color=blue size=3>' ||
                htf.bold( '과목번호 ') ||
                '</FONT>' || htf.formtext('the_sub_num',15,15) ||
                '<FONT color=blue size=3>' ||
                htf.bold( '를 ') ||
                '</FONT>');
htp.formsubmit(null,'삭제합니다');


--
htp.p('<TD><HR NOSHADE size="2"></TD>');
htp.br;
htp.br;
htp.br;
htp.formopen( 'state1' );
htp.formsubmit(null,'과목보기 창으로');
htp.formclose;
htp.br;
htp.br;
htp.br;
htp.p('<TD><HR NOSHADE size="2"></TD>');

htp.bodyclose;
htp.htmlclose;
exception
when no_data_found then
htp.centeropen;
htp.p('좀만 더 힘 써봐, 화이팅!!!');
when others then
htp.centeropen;
htp.p(the_sub_num||'과목의 시간이 중복되었습니다.');
htp.bold('다시 신청해 주십시오!!!');
htp.br;
htp.br;
htp.formopen('state1');
htp.formsubmit(null,'과목보기 창으로');
end;
/
show err



답변

제가생각할때는 설계를 바꾸는게 최선입니다.
현재설계가 RDB에 적합한 설계라고는 볼수 없습니다.
하지만 지금 table의 layout을 유지하고
중복되는 시간을 check하려면 방법이 없는것은 아닙니다.
다만,부적합한 설계로 인하여 구현이 어려워진다는게 문제지요..
procedure 안에서 cursor를 쓰지말고
다음 query를 이용해 보세요.
parameter는 the_sub_num,the_stu_num 을 사용합니다.
query에서 return되는 값이 0보다 크면 중복되는 시간이 이미
ord table 에 있는 겁니다.
return 값이 0이라면 더이상의 check없이 insert 하시면 됩니다.

SELECT COUNT(*)
FROM (SELECT DECODE(RNO,1,T1,2,T2,3,T3,4,T4,5,T5) ATIME
      FROM  (select 'A'||SUBSTRB(TIME1,NO,1) T1,
                    'B'||SUBSTRB(TIME2,NO,1) T2,
                    'C'||SUBSTRB(TIME3,NO,1) T3,
                    'D'||SUBSTRB(TIME4,NO,1) T4,
                    'E'||SUBSTRB(TIME5,NO,1) T5
             from   subject,(SELECT ROWNUM NO FROM USER_TABLES WHERE ROWNUM <= 5)
             where  sub_num = the_sub_num),
            (SELECT ROWNUM RNO  FROM USER_TABLES WHERE ROWNUM <= 5)
      WHERE LENGTHB(DECODE(RNO,1,T1,2,T2,3,T3,4,T4,5,T5)) > 1
      INTERSECT
      SELECT DECODE(RNO,1,T1,2,T2,3,T3,4,T4,5,T5) ATIME
      FROM  (select 'A'||SUBSTRB(TIME1,NO,1) T1,
                    'B'||SUBSTRB(TIME2,NO,1) T2,
                    'C'||SUBSTRB(TIME3,NO,1) T3,
                    'D'||SUBSTRB(TIME4,NO,1) T4,
                    'E'||SUBSTRB(TIME5,NO,1) T5
             from   ORD,(SELECT ROWNUM NO FROM USER_TABLES WHERE ROWNUM <= 5)
             where  sTu_num = the_stu_num),
            (SELECT ROWNUM RNO  FROM USER_TABLES WHERE ROWNUM <= 5)
      WHERE LENGTHB(DECODE(RNO,1,T1,2,T2,3,T3,4,T4,5,T5)) > 1
     )
위로