뭐 요즘 들어 AI, 가상 현실 이런 식으로 명시적으로 미래 지향적으로 얘긴 하지만 생각보다 컴퓨터 속의 세상은 처음 생겼을 때부터 현실과 많이 닮은 방식을 지향하며 이루어지지 않았나 싶다. 사람도 태어났을 때부터 다른 사람들이 만들어 놓은 현실에 적응하면서 살고 있고, 컴퓨터라는 가상의 도구 또한 딱히 그 현실을 벗어나서는 의미가 없을 것 같기도 하기 때문이다. 요즘은 반대로 데이터 안의 세상이 현실의 여러가지 규칙과 물리적인 부분들을 대체할 수 있다고 얘기하고 있고 말이다.
그런 측면에서 보면 데이터베이스에 질문을 던지는 쿼리는 우리가 현실에서 물건을 찾을 때와도 비슷하다고 볼 수 있다. 아래와 같이 내 방안에 있는 서랍 안에서 야구 공을 가져오도록 다른 누구에게 부탁 한다고 생각해 보자. 아마도 "우리 집에 가서 내 방에서 서랍장이 있는데 위에서 두 번째 서랍을 열어보면 오른 쪽에 야구 공이 하나 있을 거야" 라고 표현할 수 있을 것이다. 이걸 쿼리에서 쓰이는 용어로 대충 치환해 보면 "특정 서버의 특정 데이터베이스에서 특정 테이블을 찾아서 특정 위치에 있는 특정 컬럼의 정보를 가져와 줄래?" 와 비슷하다.

또 하나 생각할 점은 해당 기술이 영어를 기반으로 만들어졌으므로 영어에서 쓰이는 여러 등가되는 단어로 구성되어 있다는 것이다. 예를 들어 가져와 라는 표현은 "select" 로, 어디에서 라는 단어는 "from" 으로, 특정 위치에 있는 이라는 부분은 "where" 이라는 단어로 표현된다.
일상에서 쓰는 자연스러운 영어 표현은 아니겠지만 예문을 위해 강제로 AI 한테 만들어 달라고 해 살짝 편집한 문장은 아래와 같다.
SELECT the baseball FROM the chest of drawers WHERE it is inside the second drawer
키워드를 빼고 나머지 부분을 위에 얘기한 한글로 바꾸면 아래와 같이 될테고,
SELECT "야구공" FROM "서랍장" WHERE "2번째 서랍 안에서"
전문적인 SQL 문으로만 구성하면 이렇게 될거다.
SELECT "컬럼(들)" FROM "원하는 테이블" WHERE "원하는 값을 가져오는 조건문"
위와 같은 느낌으로 쿼리를 만든다면 대충 아래와 같이 될 수 있다.
SELECT baseball FROM chest_of_drawers WHERE drawer_number = 2
이제 마지막으로 우리가 보통 보는 소문자 쿼리로 바꿔보자. 이제 이렇게 봤을때 select, from, where 이라는 단어는 SQL 에서 쓰는 고정된 문법 단어로 보이고, 나머지는 우리가 부탁할 때 사용하는 선택 할 수 있는 값으로 보인다면 성공한 것이다. 선택 가능한 저 값들도 아무거나 들어갈 순 없고 정해진 장소를 묘사하는 특정한 의미를 가진 표현들만 들어갈 수 있다는 느낌도 조금은 들 것이다. 이 부분 때문에 처음에 SQL이 일종의 엄청 제한된 프롬프트엔지니어링 비슷하다고 얘기를 했었다.
select baseball from chest_of_drawers where drawer_number = 2
보통 서버나 데이터베이스의 이름은 SQL 문장 내에서는 잘 보이지 않을 수 있는데, 서버는 보통 우리가 사용하는 데이터베이스 접속 용 프로그램의 첫 연결이나, 프로그래밍 언어 환경 이라면 접속을 선언하는 구문 안에 들어가 있고, 데이터베이스는 보통 UI라면 SQL 클라이언트의 접속 후에 보이는 선택 드랍 박스 쪽에 있을 수 있고, 프로그래밍 언어라면 비슷하게 쿼리 수행 전 시작 구문 안에 들어가 있을 수 있다.
또는 데이터베이스 이름이 아래와 같이 쿼리에 끼워 있을 수도 있다. 뭐 조금 더 나아가면 데이터베이스와 테이블 사이에도 사용자라는 항목이 추가로 들어갈 수도 있지만 그건 지금은 괜히 복잡해 만 지니 생각하지 말아보자.
select baseball from my_room.chest_of_drawers where drawer_number = 2
그 다음에는 테이터를 넣는 쿼리를 생각해 보자.
이건 위의 방 예제로 설명하기에는 얘기가 꼬일 것 같고, 앞 장에서 설명했던 엑셀의 테이블 모양을 떠올려 보자. 보통 우리가 엑셀에 표를 만들 때, 각 컬럼의 이름을 만들고 거기에 값들을 한 줄 한 줄 넣게 된다. 테이블 특성 상 한 줄이 모두 채워지지 않는다면 데이터를 넣는 의미가 없을 것이다.
엑셀에 그린 테이블의 이름이 아래와 같이 상품(goods) 이고 각 컬럼의 이름에 "일련번호(sequence number-seqno)", "크기(size)", "색상(color)"이 있다고 해보자.

마찬가지로 영어로 억지 예문을 만들면 아래와 같다. "너의 스케줄을 기입해 넣는데, 필요한 값들은 일, 휴식, 점심 요소 들이야."
INSERT INTO your schedule VALUES (Work, Break, Lunch)
해당 테이블에 값을 넣는 SQL 은 아래와 같을 수 있다.
INSERT INTO 테이블 VALUES (넣을 값 한줄)
단어 들을 영어로 표시해 보자
INSERT INTO goods VALUES (1, "small", "yellow")
테이블 옆에 컬럼 이름도 확실한 것을 원하는 성격이라면 명시적으로 넣을 수 있다.
INSERT INTO goods (seqno, size, color) VALUES (1, "small", "yellow")
힙 하게 특정 컬럼에만 값을 넣게 할 수도 있다. 이 구문의 경우에는 나중에 좀더 자세히 얘기하겠지만, 테이블을 처음 어떻게 만들었냐에 따라 생략한 컬럼 값 들이 특정 디폴트 값이나, 자동으로 증가되는 번호, NULL 이라고 하는 빈 의미의 값이 들어갈 수도 있다.
INSERT INTO goods (size, color) VALUES ("small", "yellow")
역시 키워드 들을 소문자로 바꾸면 아래와 같이 많이 보는 쿼리 문이 된다.
insert into goods (size, color) vaules ("small", "yellow")
데이터의 삭제도 영어 문장에서 시작해 보자.
"쇼핑 리스트에서 가격이 50달러가 넘는 아이템들을 지워줄래?"
DELETE items FROM the shopping list WHERE the price is over fifty dollars.
앞의 goods 테이블이라면 노란 색을 지정해서 지울 수 있을 것이다.
DELETE 대상 FROM goods WHERE color = "yellow"
한 가지 select 와 비슷하지만 다른 부분이 있는데, select 는 내가 원하는 특정 컬럼 만을 선택 적으로 가져올 수도 있지만, delete 는 테이블 특성 상 하나의 열을 통채로 지워야 한다(엑셀에서 하나의 셀만 선택해 값이 아닌 셀 자체를 지울 수 없는 것과 마찬가지라고 보자) 그래서 굳이 지울 "대상"이 항상 "조건에 맞는 줄" 차체라서 굳이 언급할 필요가 없기 때문에 아래와 같이 생략되어 버리게 된다.
DELETE FROM goods WHERE color = "yellow"
마찬가지로 소문자로 표시하면 아래와 같이 된다.
delete from goods where color = "yellow"
그럼 마지막으로 대망의 테이블 만들기를 살펴 보자. 이걸 맨 마지막으로 뺀 이유는 제일 설명이 복잡하기 때문이였다. 아마 처음부터 테이블을 만드는 구문을 보고 시작하면 왜 그렇게 만들어야 하는 지가 잘 마음에 안 닿아서 SQL 공부가 싫어질 가능성이 높아질 수 있다.
한번 마찬가지로 영어 문장으로 봐보자.
"상품들이라는 이름의 새 테이블을 하나 만들어 주는데, 일련 번호, 사이즈, 색상 이라는 필드로 구성되게 해줘."
CREATE a new table, named 'goods', CONSISTING OF fields for Serial Number, Size, and Color.
SQL 문은 () 기호를 사용해서 조금 더 심플하게 정리해 표현한다.
CREATE TABLE "상품들" (일련번호, 사이즈, 색상)
그리고 조금 더 이해하기 어려운 부분들이 생기게 되는데, 처음으로 데이터 형의 정의라는 프로그래밍 개념이 들어가게 된다는 것이다. 사실 데이터 조회 쪽 업무나, 조회하는 프로그램만 개발한다면 아마도 이 테이블 생성하는 구문은 꽤 늦게나 만나게 될 수도 있다. DBA 같은 쪽에서 테이블 등을 다 설계해서 생성해 주고, 사용자는 데이터를 조회하거나 넣을 수만 있을 가능성이 높기 때문이다. 사실 삭제 쿼리의 권한 또한 보통 데이터 조회만 하는 비즈니스 업무라면 거의 만날 수 없을 수도 있다.
왜 굳이 복잡하게 이름만 정하면 됬지 데이터 형의 정의라는 게 필요하냐고 하면, 그게 RDB 의 설계 철학이기 때문이다. 그래서 나중에 얘기할 NOSQL 을 보면 이 단점을 없애기 위해서 엄청 약하게 규제를 풀어준다(데이터 형이 없다는 건 아니고 내부적으로 유연하게 대처해 자동으로 처리한다고 해 보자). 대신 자유도가 높음 그만큼 또 데이터의 정확한 모습을 이해하기가 어려울 수 있다는 단점도 있다고 보기 때문에 세상에 항상 장점이 있음 그만큼 단점도 생긴다고 봐보자. 특정 장점을 위해서 특정 단점을 어느 정도 트레이드 오프해 감수했다고 생각하면 편하다.
데이터 형의 정의를 반영하면 위의 문장은 아래와 같이 된다. 컬럼의 정의에 관련된 몇 가지 키워드 들이 있기 때문에 컬럼을 보통 가독성을 위해 한 줄씩 표기 한다.
CREATE TABLE "상품들" (
데이터 형태가 숫자인 일련번호
데이터 형태가 문자인 사이즈
데이터 형태가 문자인 색상
)
테스트도 가변적(varchar)이냐 고정(char) 형태냐도 따지는 경우도 많지만 그건 뭐 나중에 보도록 하고, 위의 문장을 SQL 에서 약속된 문장으로 바꿈 아래와 같이 된다. AI 에게 나중에 실습 할 SQLITE 문법으로 만들어 달래 봤다. 밑의 데이터 형을 나타내는 키워드는 SQL 별로 조금 명칭이나 범위가 틀리다. 앞에서 얘기한 SQL 의 엄격함과 NoSQL에서 그 일부의 엄격함을 버리고 다른 장점을 차용한 것을 생각해보면, SQL 을 구현하는 데이터베이스 사이에서도 그런 약간의 차이가 있다고 보면 된다.
밑을 보면 상품들(goods) 라는 테이블을 만들면서, 일련번호(seqno)는 정수(INTEGER) 데이터 형으로, 크기(size)와 색상(color)은 텍스트(TEXT) 데이터 형으로 정의한 것을 볼 수 있다. 컬럼 간을 구분하기 위해 쉼표도 생겼다.
CREATE TABLE goods (
seqno INTEGER,
size TEXT,
color TEXT
);
SELECT 도 마찬가지지만 이렇게 모든 게 끝나면 좋을 텐데, 여기에 테이블의 컬럼 값들을 편하게 다루기 위한 몇 가지 요소들이 추가된다. 이건 사실 여기에서 다루기에는 너무 얘기가 산으로 갈 것 같아서, 실습에서 만나게 되면 그때 상황에 맞는 설명을 하기로 하고 자주 볼 수 있을 개념들만 짧게 얘기하자.
- 아까 INSERT 시 지정되지 않은 컬럼에 특정 값을 자동으로 넣게 해주는 DEFAULT 키워드가 있고
- 특정 컬럼이 반드시 값이 들어가야 한다고 정의하는 NOT NULL, 비어도 상관 없다고 정의하는 NULL 키워드도 있다
- 회원 ID 같이 이게 무조건 중복되지도 말아야 하고, 비어있지도 않아야 한다는 PRIMARY KEY 라는 개념도 있고
- 자동으로 데이터가 들어올 때마다 일련번호를 넣어주는 AUTO_INCREMENT, IDENTITY, SERIAL 이라는 키워드도 있고
- 들어가는 값을 체크해 제한하는 CHECK 라는 키워드
- 처음엔 조금 이해하기 헷갈리지만 다른 테이블의 같은 의미의 컬럼과 묶어서 무결성을 보장하려는 FOREIGN KEY 개념 등등이 있다.
사실 이런 키워드 들은 실제 테이블의 설계와 호출하는 프로그램의 관계 들을 보면서 이럴 때 이렇게 잘 쓰는구나를 느껴야지 잘 잊어버리지 않게 되는 경향이 있기도 하고 앞에 얘기했듯이 DBA팀이 실제 있는 회사 같은 경우에는 실습 때 빼고는, 실전에서 테이블 생성 권한을 가지는 경우도 드물 것이기 때문에 나중에 실습 할 때 적당히 상황을 만들어 끼워서 이해하도록 해보자.
위의 키워드 들을 적당히 버무려 넣으면, 아래와 같이 많이 복잡해 보이는 테이블 생성 문이 만들어지게 되지만 위에서 얘기 했듯이 이 요소들은 좀 더 테이블을 무결성 있게 잘 관리하기 위한 유틸리티 들을 장착한 것이라고 보면 된다.
CREATE goods (
seqno INTEGER PRIMARY KEY AUTOINCREMENT,
size TEXT NOT NULL CHECK (size IN ('small', 'midium', 'large')),
color TEXT DEFAULT 'black',
quantity INTEGER CHECK (quantity >= 0)
);
예를 들면 자동 증가 옵션(AUTOINCREMENT)이 없으면 일일이 다음 숫자를 계산하고 입력 시에도 동시에 들어오는 다른 쿼리와의 우선 순위를 고려해서 넣어줘야 하며, 빈 값이 들어가지 않거나(NOT ULL), 고유한 값이 들어가도록(PRIMARY KEY) 프로그래밍 하는 쪽에서 신경 써줘야 하는데, 이게 해당 테이블을 사용하는 불특정의 개발자들이 잘 이해해서 실수 없이 수행 하기에는 꽤 골치 아픈 일이 되기 때문에 데이터베이스 쪽에서 알아서 안전하게 챙길 수 있게 유용한 기능을 만들었다고 보면 된다.
뭐 정말 간단하게 다른 예와 비교하면 회의실 예약 시스템이 누가 예약을 하던 중복 예약은 못하게 막는 것과 비슷하게 기본 설계 로직 같은 게 들어갔다고 봐도 된다.
여기까지 왔을 때 잊지 말아야 하는 중요한 부분은 위의 복잡해 보이는 생성 쿼리도 사실은 처음 얘기한 아래의 간단한 문장에서 시작한 거라는 것이다. 그럼 복잡해 보이는 모양에 홀려 길을 잃을 가능성이 적어진다고 본다.
CREATE TABLE "상품들" (일련번호, 사이즈, 색상)
여기까지 오면 SQL 책에서 맨날 얘기하는 어려워 보이는 CRUD(Create, Read, Update, Delete) 에 대해서 기초를 다 이해를 했다고 봐도 된다. 무엇보다도 문법 적으로 딱딱해 보이는 부분에 대해서 좀 거부감이 사라졌기를 기대한다. 물론 저 SELECT 와 FROM 사이의 원하는 컬럼을 지정하는 부분과 WHERE 키워드 뒤의 위치를 찾는 부분에 몇 가지 variation 을 만들어 주는 추가 키워드들이 있긴 하다. 하지만 그건 앞의 CREATE 문에서 좀 더 안전한 테이블 데이터의 관리를 위해 NOT NULL, DEFAULT 같은 여러 키워드들이 추가된 것처럼, 좀 더 정교하고 의미 있는 조회 쿼리를 만들어 내기 위한 애드온 기능이라고 생각하면 맘에 편할 것이다.
추가 키워드 들과 얽힌 SELECT 문을 더 깊이 들어가기 전에 이젠 하나의 테이블을 벗어나서 테이블 간의 관계를 따지는 키워드 들을 먼저 살펴봐야 할 것 같다. 다음엔 테이블 간의 관계에 대한 키워드들이 왜 나왔을 지를 살펴보도록 하고 너무 길어지기 전에 이번 글은 마무리를 하려 한다.
- Fin -
'프로그래밍' 카테고리의 다른 글
| SQL 이해해보기 #01 - 데이터베이스와 테이블 이해하기 (0) | 2025.12.21 |
|---|---|
| SQL 이해해보기 - 들어가면서 (0) | 2025.12.21 |
| [책소개] 버그 정글을 헤쳐 가기 위한 테스터 지침서 (0) | 2022.09.04 |
| 구글로 공부하는 파이썬 - 부록 (IIS, Apache 로 Flask 돌리기) (0) | 2019.02.04 |
| [책 출간 안내] 구글로 공부하는 파이썬 (25) | 2018.03.02 |