어제 데이터베이스 시험을 봤습니다. 9시부터 5시반까지 정말 긴 시간동안 고민하여 코드를 작성하였습니다. 테이블 구분을 제대로 못해서 오류가 발생한 경우도 있고 sql의 join을 자유자재로 활용하지 못해 오류가 발생한 경우가 있어 긴 시간동안 어려움을 겪었습니다...
다시 돌아오면,, 시험 문제와 제가 작성한 코드에 대해 공유하려고 합니다. 다른 방식이 있다면 공유부탁드릴게요.
※ 실제로 코드 구현했을 때는 이상없이 잘 구현됐는데 이상이 있으면 알려주세요....
문제는 다음과 같습니다.
주어진 요구 사항을 확인한 후, 문제의 답안을 작성하세요
다음의 요구사항에 따라 제공된 필드를 참고하여 학생관리 프로그램의 시나리오를 자유롭게 만들고 프로그램을 작성하세요.
(학생 테이블 필드 : 학번, 이름, 연락처, 이메일, 주소, 등록된 날짜)
(성적 테이블 필드 : 학번, 자바점수, 파이썬점수, C언어점수, 등록된 날짜, 총점, 평균)
메뉴: 학생등록, 학생리스트, 학생정보수정, 학생정보삭제, 점수등록, 점수수정, 점수삭제, 프로그램종료
1. 학생을 등록한다. (10점)
2. 학생의 등록된 정보를 학번순 오름차순으로 출력한다. (15점)
(단, 성적테이블에 학생 점수가 등록되어 있는 경우 학과점수와, 총점, 평균을 모두 출력한다.)
3. 학생정보를 수정한다. (10점)
4. 학생정보를 삭제한다. 학생정보를 삭제할 경우 점수도 같이 삭제한다. (10점)
5. 학생정보를 검색한다. (10점)
6. 학생점수를 등록한다. 점수를 등록할 때 총점, 평균을 계산하여 같이 저장한다. (10점)
7. 학생점수를 수정한다. 점수를 수정할 경우 총점, 평균을 계산하여 같이 저장한다. (10점)
8. 학생점수를 삭제한다. (10점)
9. 클래스를 사용하여 코드를 작성한다. (15점)
* 아래 내용을 확인해주세요. (아래 내용이 작성되지 않을 경우 부분 감점)
1. 모든 키는 "학번" 필드를 사용. (학생테이블의 학번은 기본키로 등록, 점수테이블의 학번은 외래키로 등록한다.)
2. 학번 문자열이다.
우선 MySQL을 이용하여 데이터 베이스를 생성한 후 학생 테이블, 성적 테이블을 만들어 각 테이블에 문제에서 요구한 필드들을 생성합니다.
학생 테이블 필드 : 학번, 이름, 연락처, 이메일, 주소, 등록된 날짜
성적 테이블 필드 : 학번, 자바점수, 파이썬점수, C언어점수, 등록된 날짜, 총점, 평균
test 데이터 베이스를 생성합니다. -> students, scores 테이블을 생성합니다. -> 각 테이블에 필드를 생성하며 제약 조건도 같이 고려하여 작성합니다.(시험을 안 본 학생인 경우에는 null이 발생할 수 있어 scores 테이블에는 not null을 설정하지 않았습니다.)
데이터 베이스를 생성하였으니 이제 파이썬 코드로 데이터 베이스에 연결하여 입력, 수정, 삭제 등 실행해보겠습니다. 이젠에 DB를 이용한 단어장에서처럼 set,get 메소드를 활용하여 입력값에 접근하도록 하겠습니다.
regdate의 경우에는 default now()로 설정되어 있기 떄문에 필드에 값이 입력될 때마다 자동으로 시간이 입력됩니다. 따라서 주피터에서 출력을 원하는 경우에는 select 쿼리를 이용하여 출력하면 됩니다.
우선 코드를 먼저 소개한 후 클래스별로 나눠서 설명드리도록 하겠습니다.
코드는 위의 사진들과 같습니다.
이제부터 클래스마다 설명을 붙여 왜 이렇게 코드를 작성했는지 또는 어떤 의도인지를 설명할까 합니다.
코드를 작성할 때 class Manage_Stu, Manage_Scr 생성후 class Menu를 생성하였습니다. 1~10번까지의 메뉴의 메소드를 포함하는 클래스를 만들어야 한다는 생각을 했습니다. 따라서 메소드를 내포하고 있는 클래스로 연결할 self.service또는 self.execute를 생성자에 작성합니다.
메뉴 1번부터 차례로 보겠습니다.
사용자가 1을 선택시 self.service.registerStu()로 옵니다. 생성자에서 self.service = manageservice_Stu()로 정의하였기 때문에 manageservice_Stu 클래스로가서 registerStu()로 올라갑니다.
manageservice_Stu클래스의 생성자를 만듭니다.
그 다음 registerStu 메소드의 코드를 차례로 실행합니다. 사용자에게 입력 받은 값들에 접근하기 위해 set,get 메소드를 사용해야 합니다. 따라서 datas 객체를 생성하여 Manage_Stu클래스 set,get메소드를 호출하게 합니다. id, name, hp, email, address1, addrress2를 Manage_Stu 인자로 정의합니다.
생성자에서 self.info = Functions_Stu()로 정의하였으니 self.info.insert(datas)를 통해 Functions_Stu 클래스의 insert 메소드를 datas를 인자를 가지고 호출합니다. 또 위로 올라가 Functions_Stu 클래스로 올라가서 살펴보겠습니다.
sql에 연결하기 위한 코드를 작성한 후 mysql에 연동이 되었다면 sql쿼리를 작성하여 값을 등록하도록 합니다. insert 쿼리는 mysql테이블 필드안에 데이터 입력을 하는 명령문이기 때문에 insert를 이용하여 사용자가 입력한 값을 mysql에 저장합니다. 이것으로 1 학생등록을 선택시에 데이터 베이스에 학생 정보 등록이 정상적으로 이루어졌습니다.
다음으로 2 학생 리스트입니다. 학생 리스트는 등록된 학생 정보를 출력해주는 메뉴입니다.
2를 선택시 self.service.exportStu()를 마주하게 됩니다. 이는 manageservice_Stu 클래스의 exportStu메소드를 호출하기에 manageservice_Stu 클래스로 올라가 살펴보겠습니다.
exportStu 메소드 첫 행을 보면 datas = self.info.selectAll()인 것을 확인할 수 있습니다. manageservice_Stu 클래스의 생성자에서 self.info = Functions_Stu()로 정의했기 때문에 self.info.selectAll()이 Functions_Stu 클래스의 selectAll 메소드를 호출합니다.
이때 문제에서 ' 성적테이블에 학생 점수가 등록되어 있는 경우 학과점수와, 총점, 평균을 모두 출력한다.'라고 했으므로 이를 고려하여 코드를 작성해야 합니다. select 쿼리를 작성할 때 students 테이블 뿐만 아니라 scores 테이블의 필드도 불러오도록 설정해야 하므로 join을 사용합니다. scores테이블은 students 테이블에 종속적이기 때문에 join중에서도 left join을 사용합니다.이때 id가 scores 테이블에서 외래 키로 사용되므로 on s.id=r.id로 설정합니다.
다시 exportStu 메소드로 돌아옵니다.
점수등록이 되어있다면 if문이 실행될 것이고 점수등록이 되어 있지 않다면 if문이 실행되지 않을 것으로 예상됩니다. 따라서 문제의 요구대로 코드를 잘 짠 것 같습니다.
순서 상으로는 학생 정보 수정이 맞지만 학생 정보 수정이 실행하기 위해 학생 정보 조회의 메소드가 선행되어야 하기 때문에 순서를 살짝 바꿨습니다.
self.service = manageservice_Stu()로 정의되어 있기에 manageservice_Stu 클래스의 searchStu 메소드를 호출합니다.
searchStu의 메소드를 호출하여 차례로 실행합니다. 사용자에게 학번을 입력받은 후 datas = self.info.search(id)를 마주하게 됩니다. manageservice_Stu 클래스 생성자 self.info = Functions_Stu()로 정의하였기 때문에 Functions_Stu 클래스의 search메소드를 호출합니다.
MySQL에 등록된 학생정보를 select 쿼리를 이용하여 출력합니다. fetchall메소드를 통해 row에 등록된 정보가 담깁니다. 다시 searchStu메소드로 돌아와 row가 datas변수에 저장됩니다. for문을 통해 등록된 정보가 모두 출력됩니다.
마찬가지로 3 학생정보수정을 선택시 self.service.modifyStu()에 의해 manageservice_Stu 클래스의 modifyStu메소드를 호출합니다.
학생 정보 수정을 위해 학생의 학번을 입력한 후 또 datas 변수에 self.info.search(id)를 담은 것을 확인할 수 있습니다. mananageservice_Stu 클래스의 생성자 생성할 때에 self.info = Functions_Stu()로 정의했으므로 Functions_Stu 클래스의 search를 호출합니다.
사용자가 입력한 id를 가지고 와서 사용자가 입력한 id에 해당되는 mysql에 등록된 데이터들을 출력합니다. 출력한 값을 datas 변수에 저장합니다. 값이 있다면 다른 변수들을 입력받은 후 self.info.modify(datas)를 마주하게됩니다.
sql의 update 쿼리를 이용하여 datas 변수에 저장된 id, name, hp, email, address1, address2를 입력받은 값 토대로 수정합니다. 이때 입력받은 값이 정상적으로 mysql 데이터베이스에 수정되지 않았다면 result = 0으로 else를 따를 것입니다. 수정되었다면 '학생 정보가 수정되었습니다.'를 출력합니다.
마찬가지로 5 학생정보수정을 선택시 self.service.deleteStu()에 의해 manageservice_Stu 클래스의 deleteStu메소드를 호출합니다.
삭제할 학생 학번을 사용자에게 입력 받은 후 self.info.search(id)를 마주합니다. mananageservice_Stu 클래스의 생성자 생성할 때에 self.info = Functions_Stu()로 정의했으므로 Functions_Stu 클래스의 search 메소드를 호출합니다.
등록된 학생이 있다면 self.info.delete(id)를 통해 delete 메소드를 호출합니다.
여기서! 문제에서 요구한 조건을 만족해야 합니다. 문제에서 ' 학생정보를 삭제한다. 학생정보를 삭제할 경우 점수도 같이 삭제한다. '라는 조건을 제시했습니다. 이를 위해 delete문을 두 차례 사용합니다. 이때 scores 테이블의 내용을 삭제 후 students테이블 내용을 삭제하도록 설정합니다. 그 이유는 scores 테이블의 id가 students 테이블의 id를 참조하고 있어 종속되어 있기 때문입니다. 만일 students 테이블 데이터 삭제 후 scores 테이블 삭제하게 된다면 없는 대상에 정보가 담겨 있는 상태가 발생할 수 있습니다.
두 개의 delete 명령문을 통해 학생정보를 삭제하고 만일 점수까지 등록되어있다면 점수까지 함께 삭제됩니다.
지금부터는 scores 테이블에 점수를 등록합니다.
생성자에서 self.execute = manageservice_Scr()으로 정의했으므로 manageservice_Scr 클래스의 registerScr메소드를 호출합니다.
사용자에게 학번, 자바 점수, 파이썬 점수, c언어 점수를 입력 받은 후 ttl,avg 변수에 점수의 합과 평균값을 저장합니다. 이때 파이썬 연산자를 활용합니다.
그 후 grades 객체를 생성합니다. manageservice_Scr클래스 생성자 self.stat = Functions_Scr()으로 정의했으므로 self.stat.insert(grades)를 통해 Functions_Scr 클래스의 insert 메소드를 호출합니다. 이때 생성한 객체 grades를 가지고 갑니다.
insert 쿼리를 이용하여 scores테이블에 사용자가 입력받은 값들을 등록합니다. grades객체를 이용하여 set, get메소드를 활용하여 직접 입력받은 값에 접근하지 않게 합니다.
메뉴 선택지 상으로 조획가 수정뒤이지만 학생 테이블에서와 마찬가지로 수정을 위해서는 조회가 선행되기 때문에 순서를 바꾸어서 살펴보겠습니다.
self.execute = manageservice_Scr() 이기 때문에 manageservice_Scr 클래스의 searchScr 메소드를 호출합니다.
사용자에게 학번을 입력받은 후 grades 객체를 생성하였습니다. grades = self.stat.search(id)이기 때문에 Functions_Scr 클래스의 search를 호출합니다.
scores 테이블에 점수가 등록되어 있다면 입력 받은 특정 학생의 학번의 자바 점수, 파이썬 점수, c언어 점수, 총합, 평균까지 출력합니다.
이를 grades 에 담아 for문을 통해 출력합니다.
마찬가지로 생성자에서 self.execute = manageservice_Scr()으로 정의했으므로 manageservice_Scr 클래스의 modifyScr메소드를 호출합니다.
위에서 처럼 grades = self.stat.search(id)를 통해 Functions_Scr 클래스의 search메소드를 호출합니다. 만약 등록이 되어 있다면 자바점수, 파이썬점수, c언어점수를 사용자에게 차례로 입력받은 후 총합, 평균을 계산하도록 설정합니다. 새로 하랑 된 값들을 grades 객체를 생성하여 Manage_Scr클래스의 인자로 입력합니다. 그 후 self.stat.modify(grades)에 의해 Functions_Scr 클래스의 modify 메소드를 호출합니다.
grades 객체를 사용하여 사용자에게 입력받은 값에 직접 접근하지 않도록 합니다. update 쿼리를 이용하여 해당 학생의 학번의 점수를 수정합니다.
마찬가지로 생성자에서 self.execute = manageservice_Scr()으로 정의했으므로 manageservice_Scr 클래스의 deleteScr메소드를 호출합니다.
grades = self.stat.search(id)를 통해 Functions_Scr 클래스의 search메소드를 호출합니다. 만약 조회할 점수가 등록되어 있다면 self.stat.delete(id)를 마주하게 됩니다. 생성자에서 self.stat = Functions_Scr()으로 정의하였으므로 Functions_Scr 클래스의 delete 메소드를 호출합니다.
delete 쿼리를 이용하여 mysql에 등록된 점수 정보를 삭제합니다. result가 0이 아니라면 점수가 삭제될 것입니다.
이것으로 파이썬, MySQL의 문법을 망라하는 문제를 풀어보았습니다. 맨 처음에 언급했듯이 수 시간동안 고민해서 코드를 작성하였기 때문에 매우 힘들었습니다...특히 (단, 성적테이블에 학생 점수가 등록되어 있는 경우 학과점수와, 총점, 평균을 모두 출력한다.)와 학생정보를 삭제한다. 학생정보를 삭제할 경우 점수도 같이 삭제한다.를 고려하여 코드를 작성할 때에 무수히 많은 에러를 경험했습니다. 알고리즘이 맞는 것 같으면 문법이 틀리고 문법이 맞는 것 같으면 알고리즘이 틀렸습니다. 이전에 DB를 이용한 단어장에서와 비슷한 내용은 어렵지 않게 짰지만 조건이 추가될 때 어려움을 겪는 것을 발견하여 코딩에서도 역시 '경험' 이 중요함을 깨달았습니다. 무수히 많은 시행착오 속에서 얻은 깨달음을 통해 코드 작성이 간결해지고 빨라질 수 있다고 생각합니다.
'2024 서울 열린데이터광장 공공데이터 활용 창업경진대회 (1) | 2024.06.10 |
---|---|
공공데이터 호출 (0) | 2024.05.03 |
DB를 활용한 단어장! (0) | 2024.03.28 |
수강 신청 (0) | 2024.03.28 |
디렉토리 관리 시나리오 (0) | 2024.03.25 |