“일단 CREATE TABLE 문이 필요하다”를 가장 빠르게

새 기능을 만들기 시작할 때, 머릿속에는 대략 어떤 테이블이 필요한지에 대한 그림이 이미 있습니다. 그것을 CREATE TABLE 문으로 옮겨 적는 일은 단순 작업이지만 의외로 시간을 잡아먹습니다. 컬럼 타입을 매번 떠올리고, MySQL과 PostgreSQL의 문법 차이를 다시 찾아보고, 외래 키 구문을 틀리기도 하죠.

테이블 설계에서 CREATE TABLE 문을 자동 생성하는 구조 | DDL 빌더

DDL 빌더는 테이블과 컬럼을 화면에서 조립하기만 하면 MySQL / PostgreSQL / SQLite 각각의 형식에 맞는 CREATE TABLE 문과 Mermaid 형식의 ER 다이어그램을 동시에 생성하는 도구입니다. JSON 샘플을 붙여넣으면 컬럼 구성을 자동으로 추론할 수도 있습니다. 모든 처리는 브라우저 내에서 이루어지며, 입력한 테이블 설계는 외부로 전송되지 않습니다.

이 글에서는 도구 내부에서 무슨 일이 일어나는지, 즉 타입이 어떻게 변환되는지JSON에서 어떻게 컬럼을 추론하는지를 구현 기준으로 설명합니다.

테이블을 만드는 세 가지 방법

  1. JSON으로 자동 생성: API 응답이나 로그의 JSON 샘플을 붙여넣으면 컬럼명·타입·기본키·NOT NULL을 자동 추론해 테이블을 추가합니다.
  2. 수동 테이블 설계: 테이블 이름·컬럼 이름·타입·PK/NOT NULL/UNIQUE/자동 증가·기본값을 화면에서 직접 편집합니다.
  3. 관계: 참조 테이블·컬럼과 대상 테이블·컬럼을 고르기만 하면 외래 키 제약과 ER 다이어그램의 연결선이 추가됩니다.

생성한 DDL은 Visual SQL Builder로 그대로 넘겨 쿼리 작성으로 이어가거나, 나중에 SQL to ER 다이어그램에 붙여넣어 구조를 다시 확인할 수 있습니다. 설계부터 쿼리 작성까지의 흐름이 브라우저 안에서 완결되는 구성입니다.

데이터베이스별로 타입이 어떻게 변환되는가

도구는 내부적으로 데이터베이스에 의존하지 않는 공통 “논리 타입”으로 테이블을 관리합니다.

export type LogicalType =
    | 'INTEGER' | 'BIGINT' | 'DECIMAL' | 'VARCHAR' | 'TEXT'
    | 'BOOLEAN' | 'DATE' | 'DATETIME' | 'JSON' | 'UUID';

DDL을 생성하는 시점에만 선택한 방언에 맞는 실제 SQL 타입으로 변환합니다. 특징적인 부분은 SQLite에 불리언 타입과 JSON 타입이 없어서 생기는 변환, 그리고 기본키 자동 증가 구문의 차이입니다.

논리 타입MySQLPostgreSQLSQLite
BOOLEANBOOLEANBOOLEANINTEGER
JSONJSONJSONBTEXT
UUIDCHAR(36)UUIDTEXT
PK + 자동 증가INT ... AUTO_INCREMENTSERIALINTEGER PRIMARY KEY AUTOINCREMENT

기본키와 자동 증가가 결합된 행이 방언 차이가 가장 큽니다. PostgreSQL은 타입 자체가 SERIAL(내부적으로는 INTEGER + 시퀀스)로 치환되고, SQLite는 INTEGER PRIMARY KEY라는 특정한 표기를 했을 때만 진짜 rowid 별칭으로서 자동 증가가 동작한다는 사양상의 제약이 있습니다. 도구는 이 세 방언의 차이를 흡수해 선택한 방언에 맞는 올바른 구문을 출력합니다.

또한 기본키로 지정한 컬럼은 NOT NULL·UNIQUE·기본값 설정이 있어도 무시되고 <타입> PRIMARY KEY로만 출력됩니다. 기본키는 정의상 이미 NOT NULL이면서 UNIQUE이기 때문입니다.

JSON 샘플에서 컬럼을 추론하는 로직

JSON 객체(또는 배열)를 붙여넣으면 각 속성의 값에서 컬럼 타입을 추론합니다. 판정 우선순위는 대략 다음과 같습니다.

  1. 값이 불리언뿐 → BOOLEAN
  2. 값이 숫자뿐 → 모두 정수면 INTEGER(2^31을 넘는 값이 있으면 BIGINT), 소수가 섞여 있으면 DECIMAL
  3. 값이 문자열뿐 → ISO 8601 날짜·시간 형식이면 DATETIME, 날짜 형식이면 DATE, UUID 형식이면 UUID, 그 외에는 VARCHAR(255자를 넘는 값이 있으면 TEXT)
  4. 값이 객체뿐 → JSON

배열로 샘플을 넘기면 여러 건의 값을 한꺼번에 판정에 사용합니다. 이를 통해 한 건만으로는 알 수 없는 NULL 허용 여부(값에 null이 섞여 있는지)나 타입의 편차(정수뿐 아니라 소수도 섞여 있는 등)를 감지할 수 있습니다.

[
  { "id": 1, "nickname": "Alice", "score": 10 },
  { "id": 2, "nickname": null, "score": 10.5 }
]

이 샘플에서는 nickname에 NULL이 섞여 있어 NOT NULL을 해제하고, score는 정수와 소수가 혼재하므로 DECIMAL로 추론됩니다.

중첩된 객체 배열은 연관 테이블로 분리된다

최상위 속성이 “객체의 배열”인 경우에는 단순히 JSON 타입 컬럼으로 처리하지 않고, 부모 테이블을 참조하는 외래 키를 가진 별도 테이블로 자동 분리합니다.

{
  "id": 1,
  "name": "Order #1",
  "items": [
    { "product": "Widget", "qty": 2 },
    { "product": "Gadget", "qty": 1 }
  ]
}

이 JSON을 orders라는 이름으로 생성하면 orders 테이블과 별개로 items 테이블이 만들어지고, items.orders_id → orders.id라는 외래 키 관계가 자동으로 설정됩니다. 주문과 그 명세 행 같은 1대다 관계를 JSON 하나에서 조립할 수 있는 형태입니다. 중첩이 2단계보다 깊은 경우에는 자동으로 테이블이 분리되지 않으므로 생성 후 수동으로 조정해 주세요.

SQL to ER 다이어그램과의 왕복으로 설계 확인하기

DDL 빌더에서 만든 테이블 구성을 MySQL 방언 DDL로 내보내고 그것을 SQL to ER 다이어그램에 붙여넣으면, 파싱 결과로 동일한 테이블·컬럼·관계가 재현됩니다. 생성한 DDL이 제대로 파싱 가능한 표준 구문인지 확인하고 싶을 때나, 나중에 구조를 다시 검토할 때 쓸 수 있는 왕복 경로입니다.

자주 묻는 질문

PK를 체크하면 NOT NULL·UNIQUE·기본값 설정은 어떻게 되나요?

기본키는 정의상 NOT NULL이면서 UNIQUE이므로, PK로 표시한 컬럼은 NOT NULL·UNIQUE·기본값 설정이 무시되고 “타입 PRIMARY KEY”(자동 증가가 켜져 있으면 AUTO_INCREMENT 등 추가)로만 출력됩니다.

생성한 DDL을 그대로 프로덕션 마이그레이션에 사용해도 되나요?

이 도구는 테이블 설계의 초안이나 리뷰 자료로 사용하는 것을 상정하고 있습니다. 인덱스, CHECK 제약, 문자셋·정렬 순서, 파티셔닝 등 실제 운영에 필요한 세부 사항은 포함되지 않으므로, 생성 후 반드시 내용을 확인하고 필요한 조정을 거친 뒤 사용하세요.

JSON에서 생성한 테이블 이름이 기존 테이블과 중복되면 어떻게 되나요?

자동으로 _2 같은 일련번호를 붙여 중복을 피합니다. 수동으로 만든 기존 테이블이 덮어써지는 일은 없습니다.


테이블 설계가 막막하다면, 먼저 가지고 있는 JSON 샘플을 붙여넣어 보세요.

DDL 빌더 사용해 보기


이 외에도 개발에 도움이 되는 다양한 도구를 제공하고 있습니다.
https://devtoolkits.app/