본문으로 바로가기

이 강좌는 bonkora님께서 작성해 주셨습니다.

시작하면서

데이터베이스하면 먼저 떠오르는 이름들이 Oracle이나 Sybase 이런 것들인데 소규모의 데이터베이스를 구축하거나 공부를 하기 위한 목적으로는 MS 액세스를 사용하는 것도 괜찮을 것 같습니다. 이런 것들에서 사용하는 SQL이 세부적으로 각 제품마다 약간씩 다른 점도 있으나 기본적인 틀은 비슷합니다. 이 강좌에서는 데이터베이스와 SQL 자체를 설명하지는 않고 Tcl/Tk의 확장패키지 중의 하나인 tclodbc를 통하여 MS 액세스의 데이터파일과 SQL을 다루는 방법만을 설명합니다.

tclodbc의 설치

MS 윈도 운영체제를 기준으로 설명합니다. 필자는 MS 윈도 XP와 ActiveTcl을 사용했습니다. 먼저 tclodbc.2.3.1.zip을 다운로드합니다. 아무 폴더에든 이 압축파일을 풀어 넣습니다.

그 후 Tclsh나 Wish에서 cd 명령으로 압축을 푼 폴더로 갑니다. 위 그림과 같이 setup.tcl 스크립트를 실행시킵니다.

Wish로 실행시켰을 때는 위 그림과 같이 ActiveTcl이 설치된 폴더의 하부 lib 폴더에 패키지를 설치했다는 메시지가 나타납니다. 이제 설치가 되었습니다.

MS 액세스에서 데이터 만들기

MS 액세스 2003을 사용하였습니다. 다른 버전을 사용할 경우에는 인터페이스가 설명과 약간 다를 수 있으나 기본적인 데이터 입력방법은 동일합니다.

먼저 메뉴에서 "새로 만들기"를 선택합니다.

그런 후 "작업 창"에서 "새 데이터베이스"를 선택합니다.

위와 같이 새로운 파일이름을 "phone" 또는 "phone.mdb"로 입력합니다.

그 후 위와 같은 창이 뜨면 "디자인 보기에서 새 테이블 만들기"를 더블클릭합니다.

첫 번째 필드이름은 "id", 데이터 형식은 "일련 번호"를 선택합니다. 이렇게 하면 번호를 따로 입력하지 않아도 자료가 새로이 입력될 경우 프로그램이 자동적으로 번호를 붙여줍니다. 1부터 차례대로 번호가 붙는데, 만약 중간의 레코드 하나를 삭제하면 하나의 번호가 비게 됩니다.

아래의 속성 부분에서 "인덱스"를 "아니요"로 선택합니다.

다음 필드이름은 "name"으로 하고 데이터 형식은 "텍스트"로 합니다. 필드 크기는 10, "필수" 속성은 "예", "빈 문자열 허용"은 "아니요", "인덱스" 속성도 "아니요"로 선택합니다.

"phone" 필드를 만들고, 필드크기를 11로 하는 것 외에는 name 필드와 같이 설정합니다. 여기에 전화번호를 넣을 것인데 번호 중간에 들어가는 하이픈('-')은 편의상 생각하지 않습니다.

"class" 필드를 만듭니다. 필드 크기를 10으로 하는 것 외에는 앞의 필드와 같습니다.

상단의 주 메뉴에서 "저장"을 선택합니다. 테이블 이름을 물어보는데 "phone"이라고 입력합니다. 그 후엔 위의 그림과 같이 기본키를 만들지 물어보는데 "아니요"를 선택한 후 마칩니다.

이제 자료를 입력할 차례입니다. 데이터베이스 창에서 "phone" 테이블을 더블클릭하여 자료입력을 위한 창을 엽니다.

위와 같이 일단 한 개의 레코드를 입력합니다. 일련 번호는 자동으로 들어가므로 입력하지 않아도 됩니다. 이제 MS 액세스를 종료합니다.

tclodbc의 기본 익히기

이제 Tclsh이나 Wish를 열어서 phone.mdb가 있는 폴더로 이동합니다. 일단 대화식으로 몇 가지 명령문들을 알아보기로 합니다. 아래에서, "%" 뒤에 오는 것은 명령, "=>" 뒤에 오는 것은 인터프리터의 응답입니다.

% package require tclodbc
=> 2.3

먼저 tclodbc를 사용한다고 말해야겠죠.

% set driver "Microsoft Access Driver (*.mdb)"
=> Microsoft Access Driver (*.mdb)

다음으로는 MS 액세스 드라이버를 driver 변수에 넣습니다.

% set dbfile "phone.mdb"
=> d:\tcl\tclodbc\phone.mdb

파일이름을 지정합니다.

% database connect db "DRIVER=$driver;DBQ=$dbfile"
=> db

"db"라는 ID로 드라이버와 파일이름으로 데이터베이스를 엽니다.

% db disconnect
=> OK

방금 열었던 데이터베이스를 닫으려면 위와 같이 합니다.

% database connect db "DRIVER=$driver;DBQ=$dbfile"
=> db

다시 데이터베이스를 엽니다.

% db "SELECT * FROM phone"
=> {1 홍길동 12312341234 가족}

이제 SQL를 사용해 봅시다. 가장 기본적인 것이 "SELECT" 명령문입니다. phone 테이블의 모든 자료를 보기 위한 SQL 명령문이 "SELECT * FROM phone"인데 이것을 tclodbc에서는 위와 같이 사용합니다. 액세스에서 입력한 하나의 레코드를 보여줍니다. 그런데 이것을 좀 더 쉽게 사용할 수 있는 방법이 있습니다. 명령문 메쏘드를 사용하는 것이 그것인데 이것은 새로운 명령문 객체를 만드는 것입니다. 예를 들어 보겠습니다.

% db statement viewall "SELECT * FROM phone"
=> viewall

위와 같이 명령하면 "viewall"이라는 새로운 명령문 객체가 생성됩니다. 쉽게 새로운 명령을 하나 만들었다고 생각하면 되겠습니다.

% viewall 
=> {1 홍길동 12312341234 가족}

이렇게 결과를 얻을 수 있습니다. 이제 id 필드에 특정한 값을 가진 레코드를 출력하는 방법을 알아보겠습니다.

% db statement viewrec "SELECT name, phone, class FROM phone WHERE id = ?" 
=> viewrec

위와 같이 viewrec이라는 새로운 명령문 객체를 만들었습니다. "WHERE" 뒤에 출력될 레코드의 조건을 지정해 주고 "SELECT" 뒤에 출력될 필드를 지정해 줍니다. 위 문장의 끝에 "?"가 있는데 이것은 인자가 들어갈 자리를 나타냅니다.

% viewrec 1 
=> {홍길동 12312341234 가족}

이렇게 하면 특정 id 값을 가진 레코드를 출력시킬 수 있습니다. 이제 새로운 레코드를 추가하는 방법을 알아보겠습니다.

% db statement insertrec "INSERT INTO phone (name, phone, class) VALUES (?, ?, ?)" 
=> insertrec

새로운 명령문 객체 insertrec를 만들었습니다. name, phone, class 세 개의 필드에 들어갈 인자를 넣어주면 새로운 레코드가 만들어집니다. id는 자동으로 채워집니다.

% insertrec [list 심순애 34534563456 친구]
=> 1

이렇게 하나의 레코드를 추가했습니다. 1개의 레코드를 추가했다고 인터프리터가 응답합니다.

% viewall 
=> {1 홍길동 12312341234 가족} {2 심순애 34534563456 친구}

레코드 전체를 보면 위와 같습니다.

% insertrec {이수일 56756785678 직장} 
=> 1

이렇게 추가해도 됩니다.

% viewall 
=> {1 홍길동 12312341234 가족} {2 심순애 34534563456 친구} {3 이수일 56756785678 직장} 
% insertrec {강감찬 78978907890 가족} 
=> 1 
% insertrec {이순신 34534563456 직장} 
=> 1 
% viewall 
=> {1 홍길동 12312341234 가족} {2 심순애 34534563456 친구} {3 이수일 56756785678 직장} {4 강감찬 78978907890 가족} {5 이순신 34534563456 직장}

이어서 몇 개의 레코드를 추가하였습니다.

% db "SELECT * FROM phone ORDER BY name" 
=> {4 강감찬 78978907890 가족} {2 심순애 34534563456 친구} {3 이수일 56756785678 직장} {5 이순신 34534563456 직장} {1 홍길동 12312341234 가족}

기존의 레코드들을 name 필드의 가나다 순에 따라 출력하면 위와 같습니다. 이제 레코드를 수정하는 방법을 알아보겠습니다.

% db statement updaterec "UPDATE phone SET name = ?, phone = ?, class = ? WHERE id = ?" 
=> updaterec

네 개의 인자를 넣어야 하는데, 마지막 인자는 수정할 레코드의 id 값이고 앞의 세 인자는 새로이 들어갈 값입니다.

% updaterec {심심해 4564564567 친구 2} 
=> 1

이렇게 두 번째 레코드의 값을 수정했습니다.

% viewrec 2 
=> {심심해 4564564567 친구}

이렇게 수정되었습니다.

% db statement deleterec "DELETE FROM phone WHERE id = ?" 
=> deleterec

레코드를 삭제하는 명령문 객체를 만들었습니다.

% deleterec 3 
=> 1

세 번째 레코드를 삭제하였습니다.

% viewall 
=> {1 홍길동 12312341234 가족} {2 심심해 4564564567 친구} {4 강감찬 78978907890 가족} {5 이순신 34534563456 직장}

이렇게 삭제되었습니다. 마지막으로 레코드의 개수를 알아보는 방법입니다.

% db "SELECT COUNT(id) FROM phone" 
=> 4

물론 새로운 명령문 객체를 만들어 사용할 수 있습니다.

간단한 프로그램 만들어 보기

실습용으로 아주 간단한 프로그램을 만들었는데 주석문을 제외하면 100행 미만의 작은 프로그램이니만치 기존의 레코드를 열람하고 수정하는 기능만을 가집니다. 레코드를 추가하고 삭제하는 기능과 테이블 형식으로 보여주는 기능을 추가한다면 그럭저럭 구색을 갖춘 프로그램이 될 것입니다. id 필드에는 1부터 마지막까지 빠지는 번호 없이 일련번호가 들어있습니다. 편의상 입력과정에서의 오류를 체크하는 기능은 넣지 않았습니다. 프로그램 전체는 다운로드하여서 보시면 될 것이니 여기서는 중요한 부분만 설명합니다. 다운로드한 mdb+tcl.zip을 풀면 phone.mdb와 phonebook.tcl이 나옵니다. 이 둘을 같은 폴더에 두고 Wish에서 phonebook.tcl을 실행시키면 됩니다.

 인터페이스는 위의 그림과 같습니다. 레코드의 내용이 들어갈 엔트리의 이름을 각각 .f1.e_name, .f1.e_phone, .f1.e_class으로 했습니다. 변수 curRec가 현재 보이는 레코드의 id를 기억합니다.

1: # 레코드에서 이름, 전화번호, 분류의 필드값을 가져올 명령문 객체를 만든다.
2: db statement viewName "SELECT name FROM phone WHERE id = ?"
3: db statement viewPhone "SELECT phone FROM phone WHERE id = ?"
4: db statement viewClass "SELECT class FROM phone WHERE id = ?"
5:
6: # 레코드의 내용을 수정할 때 쓸 명령문 객체를 만든다.
7: db statement updateRec "UPDATE phone SET name = ?, phone = ?, class = ? WHERE id = ?"

위와 같이 레코드의 내용을 가져오거나(2~4행) 수정할 때(7행) 쓸 명령문 객체를 프로그램이 시작할 때 생성시킵니다.

 1: proc viewRec {} {
 2:     global curRec totalRec
 3:
 4:      wm title . "$curRec / $totalRec"
 5:     # 엔트리의 내용을 지운다.
 6:     .f1.e_name delete 0 end
 7:     .f1.e_phone delete 0 end
 8:     .f1.e_class delete 0 end
 9:
10:     # 데이터베이스에서 값을 가져와서 엔트리에 채운다.
11:     .f1.e_name insert end [viewName $curRec]
12:     .f1.e_phone insert end [viewPhone $curRec]
13:     .f1.e_class insert end [viewClass $curRec]
14: }

6~8행에서 엔트리를 지우고 11~13행에서 앞서 만들었던 명령문 객체를 이용하여 자료를 갖고 와서 해당 엔트리에 집어넣습니다.

1: # 레코드를 수정한다.
2: proc editRec {} {
3:     global curRec
4:     # 엔트리의 값을 가져와서 레코드의 필드에 넣는다.
5:     updateRec [list [.f1.e_name get] [.f1.e_phone get] [.f1.e_class get] $curRec]
6:     tk_messageBox -message "수정하였습니다."
7: }

레코드의 수정을 수행할 프로시져입니다. 5행에서 엔트리의 내용을 갖고 와서 명령문 객체에 그것을 넘겨주어 수정하게 합니다.

mdb+tcl.zip
0.01MB
tclodbc.2.3.1.zip
0.13MB