무료 · 가입 불필요 · .mmd 파일 지원

Mermaid ER 다이어그램 편집기

ER 다이어그램은 테이블과 컬럼, 그리고 테이블끼리 어떻게 이어지는지를 보여줍니다. 대상이 데이터베이스 스키마이고 논점이 키와 관계의 수 — 일대다인지, 선택적인지, 중간 테이블을 끼는지 — 일 때 씁니다. 동작과 상속을 가진 타입을 그리고 싶다면 클래스 다이어그램이 맞습니다.

중간 테이블을 가진 주문 스키마

눈여겨볼 곳은 주문항목의 `}o--||`입니다. 다대다를, 두 테이블이 직접 이어진 척하지 않고 자기 컬럼을 가진 중간 테이블로 정직하게 표현하는 방식입니다. 단가를 주문항목에 둔 것은 상품 가격이 나중에 바뀌어도 주문 시점의 금액이 흔들리지 않게 하기 위해서이고, 이런 판단이야말로 ER이 드러내야 할 것입니다.

erDiagram
    고객 ||--o{ 주문 : "주문한다"
    주문 ||--|{ 주문항목 : "항목을 가진다"
    상품 ||--o{ 주문항목 : "참조된다"
    고객 ||--o{ 배송지 : "등록한다"

    고객 {
        int id PK
        string email UK "소문자로 저장"
        string 이름
        datetime 가입일시
    }
    주문 {
        int id PK
        int 고객id FK
        string 상태
        decimal 총액
    }
    주문항목 {
        int 주문id PK, FK
        int 상품id PK, FK
        int 수량
        decimal 단가 "주문 시점의 가격"
    }
    상품 {
        int id PK
        string 품번 UK
        string 상품명
    }
    배송지 {
        int id PK
        int 고객id FK
        string 우편번호
    }
편집기에서 열기
광고

예제로 익히기

1. 두 개체와 하나의 관계

ER의 관계는 콜론 뒤의 레이블이 필수입니다. 순서도의 간선과 달리 생략할 수 없습니다. 「고객이 주문을 주문한다」처럼 문장으로 읽히게 씁니다.

erDiagram
    고객 ||--o{ 주문 : "주문한다"
편집기에서 열기

2. 컬럼 붙이기

속성의 각 줄은 `타입 이름`이고 둘 다 생략할 수 없습니다. `PK`, `FK`, `UK`가 키를 나타내고, 끝에 붙은 따옴표 문자열은 그 컬럼의 주석이 됩니다. 타입은 한글로도 통하지만, SQL 타입을 그대로 적는 편이 구현과 대응이 잘 맞습니다.

erDiagram
    고객 ||--o{ 주문 : "주문한다"
    고객 {
        int id PK
        string email UK
        string 이름
    }
    주문 {
        int id PK
        int 고객id FK
        datetime 주문일시 "UTC로 저장"
    }
편집기에서 열기

3. 의미가 있는 관계 표기

각 개체에 가까운 두 글자가 그 개체의 개수를 나타냅니다. 이 예는 「주문에는 항목이 반드시 하나 이상 있다. 다만 고객은 한 건도 주문하지 않았을 수 있다」고 말합니다. 스키마가 실제로 지켜야 할 제약이고, 그림이 보여줘야 할 것입니다.

erDiagram
    고객 ||--o{ 주문 : "주문한다"
    주문 ||--|{ 주문항목 : "항목을 가진다"
    주문항목 }o--|| 상품 : "참조한다"
편집기에서 열기

4. 중간 테이블을 통한 다대다

Mermaid는 다대다를 직접 그릴 수 있지만, 실제 스키마에 직접적인 다대다는 거의 없습니다. 아래에 중간 테이블이 있습니다. 그것을 그리는 편이 정직하고, 관계 자체가 갖는 컬럼을 둘 자리도 생깁니다.

erDiagram
    학생 ||--o{ 수강 : "신청한다"
    강의 ||--o{ 수강 : "수강된다"
    수강 {
        int 학생id PK, FK
        int 강의id PK, FK
        datetime 신청일시
        string 성적 "채점 전에는 null"
    }
    학생 {
        int id PK
        string 이름
    }
    강의 {
        int id PK
        string 강의코드 UK
    }
편집기에서 열기

5. 자기 참조

테이블은 자기 자신과 관계를 가질 수 있습니다. 조직의 보고 체계, 카테고리 트리, 스레드형 댓글 같은 것들입니다. 양쪽 끝이 같은 개체가 되므로 관계 레이블이 평소보다 더 중요해집니다.

erDiagram
    사원 ||--o{ 사원 : "관리한다"
    사원 {
        int id PK
        int 상급자id FK "대표는 null"
        string 이름
        string 직책
    }
편집기에서 열기

ER 다이어그램 문법 요약

관계의 수는 양 끝에 두 글자씩 적고, 가운데에서 바깥으로 읽습니다. 왼쪽 두 글자가 왼쪽 개체를, 오른쪽 두 글자가 오른쪽 개체를 설명합니다.

문법
erDiagram다이어그램을 시작합니다. 대소문자를 구분합니다. `erdiagram`은 안 됩니다.
A ||--o{ B : "레이블"관계. 레이블은 필수.
||정확히 하나.
o|0 또는 1.
}|1 이상.
}o0 이상.
--식별 관계 — 실선.
..비식별 관계 — 파선.
A { ... }개체 A의 속성 블록.
int id PK속성: 타입, 이름, 그리고 선택적인 키 표시.
PK / FK / UK기본키, 외래키, 유일키.
int id PK, FK여러 키 표시는 쉼표로 구분.
string email "주석"끝에 붙은 따옴표 문자열은 컬럼 주석.
A ||--o{ B : "두 어절 레이블"띄어쓰기가 들어간 레이블에는 따옴표가 필수. 없으면 첫 공백에서 잘리고 남은 어절이 개체로 늘어납니다.
광고

ER 다이어그램을 깨뜨리는 여섯 가지 오류

ER은 여기서 다루는 여섯 종류 가운데 문법이 가장 엄격해서, 다른 그림이라면 통과할 것도 가차 없이 걸러집니다. 그러면서도 조용히 틀리는 것이 하나 있고, 한국어로 쓸 때는 그쪽에 걸리기 쉽습니다. 모두 Mermaid 11.12.2에서 재현했습니다.

보이는 증상

그려지기는 하는데 레이블이 잘리고 없던 개체가 늘어나 있다

원인

관계 레이블에 띄어쓰기가 있는데 따옴표가 없습니다. 이 지점에서 한국어는 중국어·일본어와 갈라집니다. 저 둘은 단어를 띄어 쓰지 않아 이 문제를 겪지 않지만, 한국어의 자연스러운 관계 표현은 대부분 두 어절 이상입니다. Mermaid는 오류를 내지 않고 첫 공백에서 레이블을 끊은 뒤, 남은 어절을 각각 독립된 개체로 만듭니다. 실측하면 `주문을 한다`는 「주문을」이라는 레이블과 「한다」라는 빈 개체가 됩니다.

해결

띄어쓰기가 들어간 레이블은 반드시 따옴표로 감쌉니다. 한국어에서는 사실상 항상 감싼다고 생각하는 편이 간단합니다.

잘못된 예
erDiagram
    고객 ||--o{ 주문 : 주문을 한다
고친 예
erDiagram
    고객 ||--o{ 주문 : "주문을 한다"

보이는 증상

Parse error, 끝부분: Expecting 'COLON', 'STYLE_SEPARATOR', got 'NEWLINE'

원인

관계에 레이블이 없습니다. 순서도의 간선과 달리 콜론과 레이블은 필수이고, 없으면 줄이 도중에 끝난 것으로 처리됩니다.

해결

콜론과 짧은 서술어를 붙입니다. 띄어쓰기가 있으면 따옴표도 함께.

잘못된 예
erDiagram
    고객 ||--o{ 주문
고친 예
erDiagram
    고객 ||--o{ 주문 : "주문한다"

보이는 증상

Parse error, 끝부분: got 'UNICODE_TEXT'

원인

관계 표기 토큰이 잘못됐습니다. `||`, `o|`, `}|`, `}o`(와 그 거울상)만 유효하고 나머지는 실패합니다. `oo`가 흔한 오타인데, 표기가 대칭일 거라고 기대해서 생깁니다.

해결

네 쌍 중 하나를 씁니다. `||--o{` — 정확히 하나 대 0 이상 — 이 대부분의 외래키를 덮습니다.

잘못된 예
erDiagram
    고객 ||--oo{ 주문 : "주문한다"
고친 예
erDiagram
    고객 ||--o{ 주문 : "주문한다"

보이는 증상

Parse error, 끝부분: Expecting 'ATTRIBUTE_WORD', got 'BLOCK_STOP'

원인

속성에 이름만 있고 타입이 없습니다. ER의 속성은 `타입 이름`이고 타입은 생략할 수 없습니다. 스키마 없는 데이터베이스에서 온 사람이 먼저 놀라는 부분입니다.

해결

모든 속성에 타입을 줍니다. 실제 스키마에 타입이 없다면 적당히 정해도 됩니다. `string`, `int`, `json`.

잘못된 예
erDiagram
    고객 {
        이메일
    }
고친 예
erDiagram
    고객 {
        string 이메일
    }

보이는 증상

Parse error, 끝부분: Expecting 'NON_IDENTIFYING', 'IDENTIFYING', got 'UNICODE_TEXT'

원인

관계 표기 사이의 선이 잘못됐습니다. 정확히 두 글자여야 하고, 식별 관계는 `--`, 비식별 관계는 `..`입니다. 하이픈 하나는 `--`의 짧은 표기가 아니라 그냥 문법 오류입니다.

해결

관계 표기 사이는 `--` 또는 `..`로 씁니다.

잘못된 예
erDiagram
    고객 ||-o{ 주문 : "주문한다"
고친 예
erDiagram
    고객 ||--o{ 주문 : "주문한다"

보이는 증상

관계 표기가 그려지지만 의미가 반대다

원인

각 개체에 가까운 두 글자가 그 개체의 것이라는 규칙은 거꾸로 읽기 쉬운 모양입니다. `고객 ||--o{ 주문`은 「한 고객이 0건 이상의 주문을 가진다」입니다. 이것을 `고객 }o--|| 주문`으로 뒤집으면 「모든 고객은 정확히 한 건의 주문에 속한다」고 말한 것이 되어 뜻이 통하지 않는데도 아무 일 없이 그려집니다.

해결

가운데에서 바깥으로 읽습니다. 고객에 닿아 있는 기호는 주문의 수가 아니라 고객의 수를 나타냅니다.

잘못된 예
erDiagram
    고객 }o--|| 주문 : "주문한다"
고친 예
erDiagram
    고객 ||--o{ 주문 : "주문한다"

렌더링에 관한 메모

모두 이 사이트가 쓰는 Mermaid 11.12.2에서 실측했습니다.

배치를 정하는 것은 개체 수가 아니라 관계의 모양입니다

개체가 줄줄이 이어져 있으면 세로로 긴 열이 됩니다. 실측에서 3개일 때 viewBox가 대략 116×470, 40개에서 116×7315였습니다. 그런데 같은 40개라도 하나의 중심 테이블에 모이는 형태라면 훨씬 가로로 길고 낮은 그림이 됩니다. 여기서 다루는 여섯 종류 가운데 유일하게, 크기보다 「데이터의 모양」이 그림의 모양을 정하는 종류입니다. 담기지 않는 스키마는 그리는 개수를 줄이기보다 어떤 관계를 그릴지 바꾸는 편이 잘 듣습니다.

한국어 레이블에는 따옴표가 거의 항상 필요합니다

이 페이지에서 가장 값비싼 조용한 오류라 다시 적어 둡니다. 영어의 관계 레이블은 places, contains처럼 한 단어인 경우가 많아서 영어권 문서에서는 따옴표가 장식처럼 보입니다. 중국어와 일본어도 띄어쓰기가 없어 이 문제를 비껴갑니다. 한국어만 다릅니다. 「주문을 한다」, 「항목을 가진다」처럼 두 어절 이상이 자연스럽고, 따옴표가 없으면 그대로 깨집니다. 실용적인 규칙은 하나입니다. 레이블은 언제나 따옴표로 감싸고 더 생각하지 않는 것.

한국어에는 대문자 표기라는 안전망이 없습니다

영어권에서 개체명을 대문자로 쓰는 관습은 `CUSTOMER`와 `customer`가 조용히 두 개의 상자가 되기 때문이고, 대문자로 맞춰 두면 사고가 눈에 보입니다. 한국어에는 이 수가 통하지 않습니다. 대신 효과가 있는 것은 표기의 통일뿐입니다. 띄어쓰기를 할지, `ID`인지 `id`인지, 「배송지」인지 「주소」인지. 그리기 전에 정해 두세요.

문법은 여섯 종류 가운데 가장 엄격합니다

관계 레이블도 필수, 속성의 타입도 필수, 관계 표기 토큰은 닫힌 집합입니다. 거의 무엇이든 그려지고 실수가 조용히 지나가는 간트와 비교하면, ER은 이른 단계에서 큰 소리로 실패합니다. 이것은 장점입니다. ER이 그려졌다면 그것이 의도한 그림일 가능성이 꽤 높다는 뜻입니다. 따옴표 없는 레이블이라는 두드러진 예외만 빼면요.

레이블이 HTML이라 PNG 내보내기는 다시 그립니다

개체의 속성 표는 SVG의 `<foreignObject>` 안에 그려지므로 브라우저가 캔버스에 바로 래스터화할 수 없습니다. 이 사이트의 PNG 내보내기는 예전에 이 때문에 조용히 실패해 SVG 파일을 돌려주고 있었습니다. 지금은 순수 SVG 텍스트 레이블로 다시 그린 뒤 출력하므로 원래 크기의 PNG가 제대로 나옵니다. 글자 배치만 아주 조금 다릅니다.

다른 다이어그램이 나은 경우

상속이나 인터페이스, 메서드를 나타내고 싶다면 이 그림은 맞지 않습니다. ER에는 그 어느 것도 존재하지 않습니다. 클래스 다이어그램을 쓰되, 그리고 있는 것이 테이블이 아니라 코드라는 점을 받아들이세요.

스키마가 크다면 전체를 한 장의 ER로 만드는 것은 아무도 읽지 않는 벽걸이 그림이 됩니다. 지금 설명하려는 일에 관련된 다섯 테이블만 그리고 나머지는 빼세요. 그림은 주장이지 목록이 아닙니다.

그리고 진짜 물음이 「데이터가 어떻게 저장되는가」가 아니라 「시스템 사이를 어떻게 흐르는가」라면, 시스템마다 서브그래프를 나눈 순서도가 답이 됩니다. ER로는 답할 수 없습니다.

다른 다이어그램 종류

작성 Dominik Malsch · 마지막 업데이트:

편집기 열기 →