ERD와 SQL 기초: 데이터 모델링부터 JOIN까지
작업일2026. 07

데이터 모델을 설계한 뒤에는 테이블 관계를 ERD로 문서화하고, SQL로 필요한 데이터를 조회합니다.
JOIN은 공통 키를 기준으로 여러 테이블의 데이터를 결합합니다.
기본키와 외래키로 테이블을 분리하면 데이터 중복과 불일치를 줄일 수 있습니다. 조회 시에는 필요한 데이터를 결합해야 합니다. 예를 들어 고객 이름은 customers에, 주문 상품은 orders에 있으므로 두 테이블을 연결하는 조건이 필요합니다.
이 글에서는 설계를 표현하는 ERD와 데이터를 조회하는 SQL의 기본 문법을 정리합니다. 문법 자체보다 쿼리가 처리되는 순서를 이해하는 것이 중요합니다.
ERD
ERD(Entity-Relationship Diagram)는 테이블과 테이블 사이의 관계를 시각적으로 표현한 설계 문서입니다. 테이블을 생성하기 전에 데이터 구조를 검토할 수 있으며, 구현 전 변경 비용을 줄이는 데 도움이 됩니다.
ERD는 개발·기획 등 여러 역할이 동일한 데이터 구조를 공유하는 기준이기도 합니다. 개발자는 테이블 구조로, 기획자는 업무 흐름으로 해석할 수 있습니다.
표기 요소
ERD는 개체, 속성, 관계, 카디널리티로 구성됩니다. 각 요소는 데이터 대상, 세부 정보, 연결 방식, 관계의 수를 나타냅니다.
개체는 테이블, 속성은 열로 구현됩니다. ERD를 기준으로 CREATE TABLE 문을 작성할 수 있어 설계와 구현의 대응 관계를 확인하기 쉽습니다.
실제로 그려보면
고객·주문 구조에 상품 테이블을 추가한 예시입니다. 주문 하나에는 여러 상품이 포함될 수 있고, 하나의 상품은 여러 주문에 포함될 수 있으므로 연결 테이블 order_items를 둡니다.
order_items 가 주문과 상품의 다대다를 1:N 두 개로 풀어주는 연결 테이블입니다. FK 가 붙은 열이 옆 테이블의 PK 를 가리킵니다.ERD 도구에서는 관계선 끝이 갈라진 형태로 표시되기도 합니다. 이를 까마귀발 표기법(Crow's Foot)이라고 하며, 갈라진 쪽은 여러 개(N), 선 하나로 끝나는 쪽은 하나(1)를 의미합니다.
읽는 순서
ERD를 검토할 때는 다음 항목을 순서대로 확인합니다. 다른 사람이 작성한 ERD를 이해하거나 설계를 점검할 때 동일하게 적용할 수 있습니다.
- 이 개체는 무엇을 나타내는가. 테이블 이름과 속성을 보고 어떤 데이터를 담는지 파악합니다
- 기본키는 무엇이고 유일성이 보장되는가. 각 행을 구분하는 값이 명확한지 확인합니다
- 어떤 외래키가 어떤 테이블을 참조하는가. 관계선을 따라가며 연결을 추적합니다
- 카디널리티가 1:1, 1:N, N:M 중 무엇인가. 실제 업무 상황과 맞는 관계인지 검토합니다
카디널리티는 요구사항 변경에 영향을 크게 받습니다. 예를 들어 고객과 주소를 1:1로 모델링하면 여러 배송지를 저장해야 하는 요구가 생겼을 때 구조를 변경해야 합니다. 관계는 현재 데이터가 아니라 업무 규칙을 기준으로 정합니다.
SQL
SQL(Structured Query Language)은 관계형 데이터베이스의 구조와 데이터를 정의·조회·조작하는 표준 언어입니다. PostgreSQL, MySQL, Oracle 등 DBMS마다 세부 문법은 다르지만 SELECT, JOIN 같은 핵심 구문은 공통으로 사용됩니다.
네 가지 분류
SQL 문장은 대상에 따라 네 가지로 분류합니다. 데이터베이스 구조, 데이터, 권한, 트랜잭션 제어가 기준입니다.
실습에서는 DML, 특히 SELECT를 가장 자주 사용합니다. 데이터 조회는 애플리케이션과 운영 환경에서 반복적으로 수행되는 작업입니다.
SELECT
SELECT는 조회할 열과 대상 테이블을 지정하는 구문입니다.
SELECT name, email
FROM ecom.customers;
위 쿼리는 customers 테이블에서 name과 email 열을 조회합니다. ecom.은 스키마 이름입니다. 스키마는 데이터베이스 객체를 논리적으로 구분하고, 이름 충돌과 권한 관리를 지원합니다.
SELECT *는 모든 열을 조회합니다. 운영 코드에서는 필요한 열만 명시하는 편이 좋습니다. 스키마 변경에 따른 결과 변화를 줄이고, 불필요한 데이터 전송을 피할 수 있습니다.
세미콜론(;)은 SQL 문장의 끝을 나타냅니다. 도구 설정에 따라 단일 문장은 생략할 수 있지만, 여러 문장을 실행할 때는 구분자로 필요합니다.
WHERE로 조건 걸기
WHERE는 조건에 맞는 행만 조회하도록 필터링합니다.
SELECT name, email
FROM ecom.customers
WHERE joined_at >= '2025-01-01';
위 쿼리는 2025년 1월 1일 이후에 가입한 고객을 조회합니다. 비교 연산자(=, >, <, >=, <=, <>)와 논리 연산자(AND, OR, NOT)를 조합할 수 있습니다.
문자열과 날짜 리터럴은 홑따옴표로 감쌉니다. PostgreSQL에서 겹따옴표는 식별자에 사용하므로 값에 사용하면 오류가 발생할 수 있습니다.
| 조건 | 쓰는 법 | 뜻 |
|---|---|---|
| 범위 | BETWEEN 10 AND 20 |
10 이상 20 이하 (양 끝 포함) |
| 목록 | IN ('서울', '부산') |
둘 중 하나와 같음 |
| 부분 일치 | LIKE '김%' |
김으로 시작 (%는 아무 글자 여러 개) |
| 빈 값 | IS NULL |
값이 없음 |
= NULL은 NULL 값을 비교하는 방식으로 사용할 수 없습니다. NULL과의 비교 결과는 참이나 거짓이 아닌 UNKNOWN이므로 조회 결과가 0건이 될 수 있습니다. NULL 값을 찾을 때는 IS NULL, NULL이 아닌 값을 찾을 때는 IS NOT NULL을 사용합니다.해석되는 순서
SQL의 작성 순서와 논리적 처리 순서는 다릅니다. 처리 순서를 이해하면 별칭과 집계 관련 오류를 분석하는 데 도움이 됩니다.
SELECT 에서 붙인 별칭은 그때까지 존재하지 않으므로 WHERE 에서 쓸 수 없고, ORDER BY 에서는 쓸 수 있습니다.JOIN
JOIN은 공통 열을 기준으로 두 개 이상의 테이블을 하나의 결과 집합으로 결합하는 구문입니다. 정규화로 분리한 데이터는 조회 목적에 따라 JOIN으로 결합합니다.
SELECT c.name, o.item
FROM ecom.customers c
JOIN ecom.orders o
ON c.customer_id = o.customer_id;
customers 뒤의 c와 orders 뒤의 o는 별칭입니다. 두 테이블에 customer_id처럼 같은 이름의 열이 있으면 c., o.로 소속 테이블을 명시해야 합니다.
ON에는 테이블을 연결할 조건을 지정합니다. 위 쿼리는 같은 customer_id를 가진 행을 결합하므로, 고객 정보는 해당 고객의 주문 건수만큼 결과에 나타납니다.
JOIN의 종류
주문이 없는 고객까지 조회해야 한다면 다른 JOIN 유형을 사용해야 합니다. JOIN 유형은 어느 테이블의 행을 결과에 유지할지에 따라 구분됩니다.
| 종류 | 남는 행 | 쓰는 상황 |
|---|---|---|
INNER JOIN |
양쪽에 짝이 있는 행만 | 기본값. JOIN만 적으면 이것입니다 |
LEFT JOIN |
왼쪽 테이블은 전부, 오른쪽은 짝이 있을 때만 | 주문이 없는 고객도 목록에 넣을 때 |
RIGHT JOIN |
오른쪽 테이블은 전부 | LEFT로 순서를 바꿔 쓰는 경우가 많습니다 |
FULL OUTER JOIN |
양쪽 전부 | 어느 쪽에만 있는 데이터를 찾아낼 때 |
-- 주문이 없는 고객도 함께 조회
SELECT c.name, o.item
FROM ecom.customers c
LEFT JOIN ecom.orders o
ON c.customer_id = o.customer_id;
LEFT JOIN을 사용하면 도라도 결과에 포함되고, 주문이 없는 경우 item은 NULL입니다. 후속 집계나 계산에서는 NULL 값을 고려해야 합니다.
실습 환경
실습에서는 PostgreSQL을 데이터베이스로, DBeaver를 클라이언트 도구로 사용합니다. PostgreSQL은 데이터를 저장하고 SQL을 처리하는 서버이며, DBeaver는 서버에 접속해 SQL을 실행하고 결과를 표시하는 클라이언트입니다.
- PostgreSQL: 오픈소스 관계형 DBMS입니다. 표준 SQL 지원이 넓어 학습과 실무 환경에서 많이 사용됩니다
- DBeaver: 여러 DBMS에 연결할 수 있는 데이터베이스 클라이언트입니다. ERD 생성 기능으로 테이블 관계를 확인할 수 있습니다
column "x" does not exist는 열 이름을, relation "y" does not exist는 테이블 이름과 스키마 접두어를 확인해야 한다는 의미입니다.정리하면
- ERD: 개체·속성·관계선·카디널리티 네 가지로 그립니다. 개체가 테이블, 속성이 열이 되니 그림과 코드가 그대로 대응합니다
- SQL 분류: 구조는 DDL, 데이터는 DML, 권한은 DCL, 확정과 취소는 TCL
- SELECT: 적는 순서와 처리 순서가 다릅니다.
FROM→WHERE→SELECT→ORDER BY - JOIN: 짝이 있는 행만 볼 때는
INNER, 한쪽을 전부 남길 때는LEFT - NULL:
= NULL은 조용히 0건을 돌려줍니다.IS NULL을 씁니다
SELECT와 WHERE로 데이터를 조회하고, JOIN으로 여러 테이블의 데이터를 결합합니다.참고
- PostgreSQL 공식 문서: Queries (SELECT · JOIN)
- PostgreSQL 공식 문서: Comparison Functions and Operators
- PostgreSQL 공식 문서: Schemas
- DBeaver: ERD 기능 문서
다음 글에서는 서비스 규모에서 관계형 데이터베이스의 한계를 검토하고, 벡터 DB 같은 대안을 선택하는 기준을 정리합니다.