1 탐사대 기록을 데이터베이스로
1.1 1930년대 탐사대의 고민
1930년 12월, 남극 대륙의 혹독한 추위 속에서 김대영(Dyer) 교수는 두꺼운 장갑을 낀 손으로 관측 노트에 숫자를 기록하고 있었다. 측정 장비에서 나온 수치들을 하나하나 정확히 기입하는 것은 매우 중요한 일이었다. 하지만 데이터가 쌓일수록 한 가지 문제가 생겼다.
“이 많은 데이터를 어떻게 정리하고 분석할 것인가?”
당시에는 종이 노트에 손으로 쓴 기록을 일일이 찾아가며 패턴을 찾아야 했다. 특정 측정자의 모든 기록을 찾거나, 특정 지역의 모든 측정값을 비교하는 것은 매우 번거로운 일이었다.
1.2 AI와 SQL의 첫 만남
1.2.1 AI에게 먼저 물어보기
90년이 지난 2025년. 이제 완전히 다른 도구를 손에 쥐고 있다. 종이와 펜 대신 키보드와 모니터가, 수동 계산 대신 AI와 데이터베이스가 우리 곁에 있다.
만약 Dyer 교수가 ChatGPT를 사용할 수 있었다면 어땠을까? 아마 이렇게 물어봤을 것이다: “우리 탐사대 데이터를 분석해줘. 패턴이 보이니?” 하지만 AI의 답변을 그대로 믿을 수 있을까?
실제로 확인해보자. 연세대학교 창고에서 발견된 탐사 기록들을 ChatGPT에게 먼저 물어본 다음, SQL로 검증해보는 것이다. 이 과정에서 AI의 강점과 한계, SQL 정확성이 왜 여전히 중요한지 깨닫게 될 것이다.
질문: “1930년대 남극 탐사대 데이터를 보고, 누가 가장 많은 측정을 했는지 알아봐”
ChatGPT 답변: “데이터를 보면 Dyer 교수가 탐사대 리더로서 가장 많은 측정을 수행했을 것으로 추정됩니다. 리더는 보통 전체적인 측정을 관리하고 직접 많은 측정을 담당하기 때문입니다.”
🤔 과연 이게 맞을까요?
AI의 추측이 맞는지 실제 데이터로 확인해보기 위해서는 데이터베이스가 필요하다.
하지만 왜 데이터베이스일까? 1930년대 남극 탐사대의 수천 건 측정 데이터를 분석하는 상황을 생각해보자. 기본적으로 3가지 선택 옵션이 있다:
텍스트 파일은 생성하기 가장 쉽고 버젼 제어와 궁합이 맞다. 하지만 “Dyer가 측정한 염도 평균은?”이나 “어느 지역에서 방사능이 가장 높았는가?” 같은 질문에 답하려면 별도의 프로그램을 작성해야 한다.
스프레드쉬트는 시각적으로 편리하고 간단한 계산에 적합하다. 그러나 수천 행의 데이터에서 여러 테이블 간의 복잡한 관계를 분석하기에는 한계가 있다.
데이터베이스만이 복잡한 질문들을 SQL 한 줄로 즉시 답할 수 있다. “누가 가장 많이 측정했나?”, “지역별 평균 방사능 수치는?”, “결측 데이터가 있는 측정은 몇 개인가?” - 이 모든 질문이 간단한 쿼리로 해결된다.
그림 1.1 에서 보듯이, 1930년대 탐사 데이터의 복잡한 관계형 분석과 대용량 데이터 처리가 필요한 상황에서 데이터베이스가 최적의 선택이다. 이제 실제로 데이터를 데이터베이스에 넣어서 어떻게 검색하고 분석하는지 알아보자.
1.3 SQL 기초 개념
관계형 데이터베이스(relational database)는 정보를 테이블(tables) 형태로 체계적으로 저장하고 관리하는 시스템이다. 각 테이블은 필드(fields)라 불리는 열(column)과 레코드(records)라 불리는 행(row)으로 구성되어, 마치 잘 정리된 표처럼 데이터를 담고 있다.
스프레드시트에서는 셀에 수식을 입력해 계산하지만, 데이터베이스에서는 쿼리(queries, 질의)라는 명령문을 사용한다. 이 쿼리를 받아 처리하는 것이 바로 데이터베이스 관리자(database manager)다. 이 프로그램은 사용자의 요청을 해석하고, 필요한 데이터를 찾아 계산한 뒤, 그 결과를 다시 테이블 형태로 돌려준다. 이렇게 반환된 결과는 또 다른 쿼리의 입력이 될 수 있어, 복잡한 분석도 단계적으로 수행할 수 있다.
IBM DB2, PostgreSQL, MySQL, Microsoft Access, SQLite 등 각 데이터베이스 시스템은 고유한 방식으로 데이터를 저장한다. 따라서 한 시스템의 데이터를 다른 시스템에서 바로 사용할 수는 없다. 하지만 걱정할 필요는 없다 - 모든 시스템이 가져오기(import)와 내보내기(export) 기능을 제공하므로, 필요하면 언제든 데이터를 이동시킬 수 있다.
이러한 쿼리는 SQL(Structured Query Language, 구조적 질의 언어)로 작성한다. SQL은 수백 가지 방법으로 데이터를 분석하고 재조합할 수 있는 강력한 언어다. 이 책에서는 데이터 과학자가 실무에서 가장 많이 사용하는 핵심 기능들을 중점적으로 다룰 것이다.
1.3.1 탐사대 데이터베이스 구조
이제 연세대학교 창고에서 발견된 탐사 기록들이 어떻게 데이터베이스로 구성되어 있는지 살펴보자.
놀랍게도 90년 전 1930년대 과학자들의 데이터 기록 방식은 현대적인 관계형 데이터베이스 설계 원칙을 그대로 따르고 있다. 이들은 모든 정보를 하나의 거대한 표에 몰아넣는 대신, 데이터의 성격에 따라 체계적으로 분리하여 기록했다. 탐사대원 정보, 측정 지점 위치, 방문 기록, 실제 측정값을 각각 독립된 표로 관리함으로써 중복을 최소화하고 데이터 무결성을 유지했던 것이다.
이러한 구조는 오늘날 우리가 사용하는 관계형 데이터베이스의 핵심 원리와 정확히 일치한다. 각 테이블은 고유한 역할을 담당하면서도 서로 유기적으로 연결되어 있어, 복잡한 질문들에 대한 답을 효율적으로 찾을 수 있게 해준다. 예를 들어 “김대영 교수가 DR-3 지점에서 측정한 모든 방사능 수치”를 찾으려면, Person → Survey → Visited → Site 테이블을 연결하여 한 번의 쿼리로 답을 얻을 수 있다.
1930년대 과학자들이 체계적으로 기록한 데이터는 다음과 같은 4개의 테이블로 구성되어 있다:
Person: 연희전문학교 탐사대원들의 정보. id
는 각 탐사대원의 고유 식별자다.
id | personal | family |
---|---|---|
dyer | William | Dyer |
pb | Frank | Pabodie |
lake | Anderson | Lake |
roe | Valentina | Roerich |
danforth | Frank | Danforth |
김대영(Dyer) 교수, 박봉식(Pabodie) 엔지니어, 레이크(Lake) 고고학자, 로이치(Roerich) 생물학자, 단포스(Danforth) 대학원생
Site: 측정값이 기록된 sites
의 위치를 나타낸다.
name | lat | long |
---|---|---|
DR-1 | -49.85 | -128.57 |
DR-3 | -47.15 | -126.72 |
MSK-4 | -48.87 | -123.4 |
Visited: 측정 위지에서 측정값이 기록된 구체적인 위치와 날짜에 대한 특정 식별 id
를 나타낸다.
id | site | dated |
---|---|---|
619 | DR-1 | 1927-02-08 |
622 | DR-1 | 1927-02-10 |
734 | DR-3 | 1930-01-07 |
735 | DR-3 | 1930-01-12 |
751 | DR-3 | 1930-02-26 |
752 | DR-3 | -null- |
837 | MSK-4 | 1932-01-14 |
844 | DR-1 | 1932-03-22 |
Survey: 각 측정지의 정확한 위치에서 취한 측정값들로, taken
으로 식별된다. quant
필드는 ‘양’을 의미하는 줄임말로 측정 대상을 나타낸다. 값은 각각 ’방사능’, ‘염도’, ’온도’를 의미하는 rad
, sal
, temp
로 표시된다.
taken | person | quant | reading |
---|---|---|---|
619 | dyer | rad | 9.82 |
619 | dyer | sal | 0.13 |
622 | dyer | rad | 7.8 |
622 | dyer | sal | 0.09 |
734 | pb | rad | 8.41 |
734 | lake | sal | 0.05 |
734 | pb | temp | -21.5 |
735 | pb | rad | 7.22 |
735 | -null- | sal | 0.06 |
735 | -null- | temp | -26.0 |
751 | pb | rad | 4.35 |
751 | pb | temp | -18.5 |
751 | lake | sal | 0.1 |
752 | lake | rad | 2.19 |
752 | lake | sal | 0.09 |
752 | lake | temp | -16.0 |
752 | roe | sal | 41.6 |
837 | lake | rad | 1.46 |
837 | lake | sal | 0.21 |
837 | roe | sal | 22.5 |
844 | roe | rad | 11.25 |
3개 항목 (Visited
테이블에서 1개, Survey
테이블에서 2개)은 실제 데이터가 아닌 특별한 -null- 항목을 가지고 있다. 왜냐하면 어떠한 값도 담고 있지 않아서 그렇다. 뒤에서 결측값(missing)을 다시 다룰 것이다.
1.4 데이터베이스 접속과 탐색
1930년대 탐사대 데이터가 어떻게 구성되어 있는지 확인했으니, 이제 실제로 데이터베이스에 접속해서 탐색해보자. 이 과정에서 SQLite라는 경량 데이터베이스 시스템을 사용할 것이다. SQLite는 별도의 서버 설치 없이 파일 하나로 전체 데이터베이스를 관리할 수 있어, 학습과 개발에 매우 적합하다.
1.4.1 SQLite 데이터베이스 접속
먼저 survey.db
파일이 있는 디렉토리로 이동해야 한다. 쉘 명령으로 작업 디렉토리를 변경한다. 만약 바탕화면에 저장했다면 다음 명령어를 사용한다.
$ cd Desktop
$ ls | grep survey.db
survey.db
파일이 확인되면 SQLite 명령줄 도구로 데이터베이스에 접속한다.
$ sqlite3 survey.db
SQLite version 3.8.8 2015-01-16 12:08:06
Enter ".help" for usage hints.
sqlite>
이 명령은 SQLite에게 survey.db
파일의 데이터베이스를 열고 대화형 모드로 진입하라고 지시한다. sqlite>
프롬프트가 나타나면 성공적으로 접속된 것이다.
1.4.2 데이터베이스 구조 탐색
SQLite에서는 SQL 명령어 외에도 시스템 관리를 위한 특별한 명령어들을 제공한다. 이런 명령어들은 점(.
)으로 시작해서 SQL 쿼리와 구별된다.
먼저 데이터베이스에 어떤 테이블들이 있는지 확인해보자.
tables .
Person Site Survey Visited
예상했던 4개의 테이블이 모두 있는 것을 확인할 수 있다. 이제 각 테이블이 어떤 구조로 되어 있는지 자세히 살펴보자. .schema
명령어는 테이블을 생성할 때 사용된 SQL 문을 보여주어, 각 칼럼의 이름과 자료형을 확인할 수 있다.
schema .
CREATE TABLE Person(
ident text,
personal text,
family text
);
CREATE TABLE Site(
name text,
lat real,
long real
);
CREATE TABLE Visited(
ident integer,
site text,
dated text
);
CREATE TABLE Survey(
taken integer,
person text,
quant text,
reading real
);
이 출력에서 각 테이블의 구조를 명확히 파악할 수 있다. 예를 들어 Person 테이블은 세 개의 칼럼을 가지고 있다:
- ident는 text 자료형 (탐사대원 식별자)
- personal는 text 자료형 (이름)
- family는 text 자료형 (성)
각 테이블의 구조를 보면 앞서 살펴본 ERD 다이어그램과 정확히 일치하는 것을 확인할 수 있다. 1930년대 탐사대원들이 얼마나 체계적으로 데이터를 설계했는지 알 수 있다.
실제 데이터를 쿼리하기 전에 SQLite의 출력 형식을 조정해서 가독성을 높여보자.
mode column
.header on .
첫 번째 명령은 데이터를 칼럼 형태로 정렬해서 보여주고, 두 번째 명령은 칼럼 이름을 헤더로 표시한다. 이렇게 설정하면 쿼리 결과를 훨씬 읽기 쉽게 만들 수 있다.
매번 이런 설정을 반복하기 싫다면, 홈 디렉토리에 .sqliterc
파일을 만들어서 위 명령어들을 저장해두면 된다:
- 윈도우:
C:\Users\<yourusername>.sqliterc
- 리눅스/맥:
/Users/<yourusername>.sqliterc
이제 탐사대 데이터베이스에 성공적으로 접속했고, 구조도 파악했다. 다음 단계에서는 실제로 SQL 쿼리를 작성해서 데이터를 조회하고 분석해보자.
작업을 마치고 SQLite를 종료하려면 .quit
또는 .exit
명령을 사용한다.
1.5 AI 추측 SQL로 검증
이제 ChatGPT의 추측을 실제 데이터로 검증해볼 시간이다. “누가 가장 많은 측정을 했는가?” 라는 질문에 과연 “리더인 Dyer 교수가 가장 많았을 것”이라는 AI의 추측이 맞을까?
먼저 우리 탐사대에 누가 있는지 확인해보자. SQL의 가장 기본적인 명령어인 SELECT
문을 사용해서 Person 테이블에서 탐사대원들의 이름을 조회한다:
SELECT family, personal FROM Person;
family | personal |
---|---|
Dyer | William |
Pabodie | Frank |
Lake | Anderson |
Roerich | Valentina |
Danforth | Frank |
5명의 탐사대원이 확인되었다. 1930년 남극의 혹독한 추위 속에서 과학적 탐험을 수행했던 용감한 연구자들이다. 그런데 이들 중 누가 가장 많은 측정을 했을까? 이를 알아내려면 실제 측정 데이터가 담긴 Survey 테이블을 살펴봐야 한다:
SELECT * FROM Survey;
SELECT *
는 테이블의 모든 칼럼을 선택한다는 의미다. 탐색적 분석에는 유용하지만, 실제 운영에서는 필요한 칼럼만 명시하는 것이 좋다.
Survey 테이블에는 21개의 측정 기록이 들어있다. 방사능(rad), 염도(sal), 온도(temp) 측정값들이 각 탐사대원별로 기록되어 있는 것을 확인할 수 있다. 그런데 흥미롭게도 일부 기록에서는 person 필드가 -null-
로 되어 있다. 이것은 나중에 살펴보기로 하고, 우선 ChatGPT의 추측을 검증해보자.
SELECT person, COUNT(*) as 측정횟수
FROM Survey
GROUP BY person
ORDER BY 측정횟수 DESC;
person | 측정횟수 |
---|---|
pb | 8 |
lake | 7 |
roe | 3 |
dyer | 2 |
결과가 나왔다! 그런데 놀랍게도 ChatGPT의 추측과는 완전히 반대였다. 리더인 Dyer 교수가 가장 많은 측정을 했을 것이라는 AI의 예상과 달리, 실제로는 pb(Pabodie) 엔지니어가 8회로 가장 많은 측정을 수행했고, Dyer 교수는 단 2회로 가장 적었다.
ChatGPT의 추측: “Dyer 교수가 리더로서 가장 많은 측정을 했을 것”
SQL 실제 결과: “pb(Pabodie)가 8회로 가장 많고, Dyer는 2회로 가장 적음”
결론: AI가 완전히 틀렸다! 실제로는 엔지니어 박봉식(Pabodie)이 가장 많은 측정을 수행했다.
왜 AI가 이렇게 틀렸을까? AI는 일반적인 패턴, 즉 “리더가 더 많은 일을 할 것”이라는 상식적 추론을 했다. 하지만 실제 1930년대 남극 탐사의 현실은 달랐다. 엔지니어인 Pabodie는 측정 장비를 직접 다루는 기술자였기 때문에 더 많은 현장 측정을 담당했고, 리더인 Dyer 교수는 전체적인 탐사 계획과 관리 업무에 집중했던 것으로 보인다. 이것이 바로 데이터로 검증하는 것의 중요성이다! 아무리 그럴듯한 추측이라도 실제 데이터 앞에서는 겸손해져야 한다.
그런데 데이터를 자세히 살펴보면서 흥미로운 점을 또 하나 발견했다. 측정 기록 중 일부에서 person
필드가 -null-
로 되어 있다는 것이다. 이는 단순한 기록 실수일까, 아니면 뭔가 다른 이유가 있는 것일까?
특히 752번 방문 기록을 보면 같은 날 여러 명이 측정을 했는데, 일부는 기록자가 명시되어 있고 일부는 누락되어 있다. 1930년 남극의 혹독한 환경에서 과학자들이 이렇게 철저하게 데이터를 관리했는데, 왜 일부 기록에서만 측정자가 빠져있을까?
우리가 SQL로 발견한 첫 번째 단서들:
- 박봉식(Pabodie) 엔지니어가 가장 많은 측정을 수행 (8회)
- 일부 측정 기록에서 person 필드가 누락됨
- 752번 방문에서 특히 이상한 패턴 발견
이것들이 의미하는 바는 무엇일까? 단순한 기록 실수인가, 아니면 탐사대에게 무슨 일이 일어났던 것인가?
AI의 추측을 깨뜨린 데이터는 이제 새로운 미스터리를 우리 앞에 제시하고 있다. 다음 장에서는 이 누락된 데이터들을 더 자세히 파헤쳐보고, 1930년대 남극 탐사대에게 정말 무슨 일이 일어났는지 알아보자…
1.6 SELECT 문 핵심 원리
지금까지 우리가 사용한 SQL 쿼리들을 다시 살펴보면서, SELECT 문이 어떻게 작동하는지 정확히 이해해보자.
위 다이어그램에서 보듯이, SELECT * FROM Person
은 Person 테이블의 모든 칼럼을 그대로 가져와서 새로운 결과 테이블을 만든다. 여기서 중요한 점은 SQL이 매우 유연하다는 것이다.
우리가 지금까지 작성한 쿼리들을 보면 일정한 패턴이 있다. 세미콜론(;
)으로 쿼리를 마무리하고, 키워드는 대문자로, 테이블명은 타이틀 케이스로 작성했다. 하지만 실제로는 SQL은 대소문자를 구분하지 않는다(case insensitive).
SeLeCt FaMiLy, PeRsOnAl FrOm PeRsOn;
family | personal |
---|---|
Dyer | William |
Pabodie | Frank |
Lake | Anderson |
Roerich | Valentina |
Danforth | Frank |
이렇게 무작위로 대소문자를 섞어 써도 정상적으로 작동한다. 하지만 가독성을 위해서는 일관된 스타일을 유지하는 것이 좋다. 일반적으로 SQL 키워드(SELECT, FROM)는 대문자로, 테이블명은 타이틀 케이스로, 칼럼명은 소문자로 작성하는 관례를 따른다.
;
를 빼먹고 엔터를 누르면 이런 상황이 발생한다:
SELECT ident FROM Person
...>
...>
SQLite가 명령이 아직 끝나지 않았다고 생각해서 계속 기다리는 것이다. 그냥 ;
를 입력하고 엔터를 누르면 해결된다!
그런데 SELECT의 진짜 매력은 칼럼을 마음대로 조작할 수 있다는 점이다. 데이터베이스에서 테이블의 행과 칼럼은 특정한 순서로 저장되어 있지 않다. 하지만 SELECT 문으로 원하는 순서대로 출력할 수 있다.
예를 들어 이름(personal)을 먼저, 성(family)을 나중에 보고 싶다면:
SELECT personal, family FROM Person;
personal | family |
---|---|
William | Dyer |
Frank | Pabodie |
Anderson | Lake |
Valentina | Roerich |
Frank | Danforth |
심지어 같은 칼럼을 여러 번 선택할 수도 있다. 왜 이런 기능이 있을까? 실제로는 계산식이나 함수를 적용할 때 유용하다:
SELECT ident, ident, ident FROM Person;
ident | ident | ident |
---|---|---|
dyer | dyer | dyer |
pb | pb | pb |
lake | lake | lake |
roe | roe | roe |
danforth | danforth | danforth |
물론 가장 간편한 방법은 *
을 사용해서 모든 칼럼을 한 번에 선택하는 것이다:
SELECT * FROM Person;
ident | personal | family |
---|---|---|
dyer | William | Dyer |
pb | Frank | Pabodie |
lake | Anderson | Lake |
roe | Valentina | Roerich |
danforth | Frank | Danforth |
이렇게 SELECT는 단순히 데이터를 “선택”하는 것 이상의 기능을 제공한다. 칼럼의 순서를 바꾸고, 원하는 칼럼만 골라내고, 심지어 같은 칼럼을 여러 번 표시할 수도 있다. 이는 데이터를 우리가 원하는 형태로 “재구성”하는 강력한 도구인 것이다.
지금까지 우리는 AI의 추측을 데이터로 검증하고, SELECT 문의 기본 원리를 이해했다. 다음 장에서는 더 복잡한 쿼리를 통해 1930년대 탐사대의 미스터리를 더 깊이 파헤쳐보자.
💭 생각해볼 점
우리는 ChatGPT의 추측이 틀렸음을 SQL로 확인했다. 그렇다면 다른 질문들도 AI에게 물어보고 SQL로 검증해보면 어떨까? 예를 들어 “가장 이상한 측정값은 무엇인가?” 같은 질문 말이다.
다음 장에서는 이 데이터들을 정렬하고 필터링하는 방법을 배우며, 탐사대의 더 깊은 비밀들을 찾아보자…