ToolPal
데이터베이스 쿼리가 표시된 노트북에서 코드를 작업하는 사람

INSERT 구문을 직접 작성하는 시대는 끝났습니다: JSON to SQL 변환기 활용법

📷 Christina Morillo / Pexels

INSERT 구문을 직접 작성하는 시대는 끝났습니다: JSON to SQL 변환기 활용법

200행짜리 JSON 내보내기를 INSERT 구문으로 수동 변환하는 건 고통스럽고 실수하기 쉽습니다. 자동화하는 방법과 주의할 점을 알아보세요.

D작성: Daniel Park2026년 4월 24일8분 소요

서드파티 서비스에서 사용자 데이터 200행을 JSON으로 내보냈습니다. 데이터베이스에는 SQL INSERT 구문이 필요합니다. 그리고 어떤 이유에서인지, 직접 작성할 생각을 하고 있습니다.

그 과정은 대략 이렇습니다. JSON 파일을 열고, 구조를 파악하고, CREATE TABLE 구문을 작성한 다음 INSERT 구문을 시작합니다. 첫 번째는 2분, 두 번째는 1분, 열 번째쯤 되면 나름의 패턴이 잡힙니다. 오십 번째쯤에는 임포트가 제약 조건 오류로 실패하기 전까지 발견하지 못할 오타가 슬그머니 들어가 있습니다.

더 좋은 방법이 있습니다. JSON to SQL 변환기는 JSON 배열을 받아 스키마를 추론하고, 바로 실행 가능한 SQL을 만들어냅니다. 컬럼명과 값이 올바르게 인용된 일괄 INSERT 구문을 포함해서요. 이 가이드에서는 도구가 하는 일, 효과적으로 사용하는 방법, 그리고 여전히 수동 정리가 필요한 부분을 살펴봅니다.

도구가 실제로 하는 일

간단히 말하면, JSON 객체 배열을 붙여넣고 SQL 방언을 선택하면 두 가지가 생성됩니다. 추론된 스키마를 바탕으로 한 CREATE TABLE 구문과 데이터를 넣는 INSERT 구문들입니다.

타입 추론이 핵심입니다. 도구는 JSON의 값을 보고 SQL 타입을 합리적으로 추측합니다. 문자열은 VARCHAR 또는 TEXT, 숫자는 INT 또는 FLOAT, 불리언은 BOOLEAN 또는 방언에 따라 TINYINT(1), null은 null 허용 VARCHAR가 됩니다.

SQL 방언 간의 포맷 차이도 자동으로 처리합니다. MySQL은 백틱으로 컬럼명을 감싸고, PostgreSQL은 큰따옴표를 사용하며, SQL Server는 텍스트 컬럼에 NVARCHAR를 씁니다.

현실적인 예시

SaaS 앱에서 JSON으로 내보낸 사용자 테이블이 있다고 해봅시다.

[
  {
    "id": 1,
    "name": "Alice Chen",
    "email": "alice@example.com",
    "age": 31,
    "active": true,
    "created_at": "2025-01-15T09:23:00Z"
  },
  {
    "id": 2,
    "name": "Ben Kowalski",
    "email": "ben@example.com",
    "age": 28,
    "active": false,
    "created_at": "2025-02-03T14:55:00Z"
  },
  {
    "id": 3,
    "name": "Sara Okonkwo",
    "email": "sara@example.com",
    "age": 34,
    "active": true,
    "created_at": "2025-03-11T08:00:00Z"
  }
]

이것을 붙여넣고 MySQL을 선택하면 다음과 같은 출력이 나옵니다.

CREATE TABLE `users` (
  `id` INT,
  `name` VARCHAR(255),
  `email` VARCHAR(255),
  `age` INT,
  `active` BOOLEAN,
  `created_at` VARCHAR(255)
);

INSERT INTO `users` (`id`, `name`, `email`, `age`, `active`, `created_at`) VALUES
(1, 'Alice Chen', 'alice@example.com', 31, TRUE, '2025-01-15T09:23:00Z'),
(2, 'Ben Kowalski', 'ben@example.com', 28, FALSE, '2025-02-03T14:55:00Z'),
(3, 'Sara Okonkwo', 'sara@example.com', 34, TRUE, '2025-03-11T08:00:00Z');

200행이라면 이 구조에 200개의 값이 들어갑니다. 붙여넣고 클릭하는 데 30초, 직접 입력했다면 15분 이상 걸렸을 작업입니다.

출력에서 몇 가지를 눈여겨보세요. created_at 필드가 DATETIME 대신 VARCHAR(255)로 타입이 잡혔습니다. 이유는 나중에 설명합니다. 테이블 이름은 기본값으로 users가 사용됩니다. CREATE TABLE에는 PRIMARY KEYNOT NULL 제약 조건이 없습니다. 이 부분은 직접 추가해야 합니다.

알아두어야 할 방언별 차이

"SQL 방언" 선택기는 생각보다 중요합니다. 데이터베이스마다 문법 차이는 작지만, 잘못 고르면 오류가 납니다.

MySQL은 백틱으로 식별자를 인용합니다. `column_name` 형태입니다. order, key, index, values 같이 MySQL 예약어와 충돌하는 컬럼명이 있을 때 특히 중요합니다. MySQL은 구버전 스키마에서 불리언에 TINYINT(1)을 사용하기도 하지만, MySQL 5.7 이상에서는 BOOLEAN이 작동합니다.

PostgreSQL은 식별자에 큰따옴표를 씁니다. "column_name" 형태입니다. 네이티브 BOOLEANTIMESTAMP WITH TIME ZONE 타입이 있습니다. 자동 증가 기본 키로는 MySQL의 AUTO_INCREMENT 대신 SERIAL 또는 BIGSERIAL을 씁니다.

SQLite는 타입에 관대합니다. 엄격한 타입 대신 "타입 어피니티"를 사용하기 때문에, TEXT로 선언된 컬럼에 정수를 저장할 수 있고 반대도 마찬가지입니다. SQLite 출력에서는 TEXTINTEGER 같은 단순한 타입명이 주로 쓰입니다.

SQL Server는 유니코드 텍스트 문자열에 VARCHAR 대신 NVARCHAR를 쓰고, 식별자를 대괄호로 감쌉니다. [column_name] 형태입니다. 불리언 값에는 BOOLEAN 대신 BIT를 사용합니다.

특정 데이터베이스로 임포트할 거라면 그 방언을 선택하세요. SQL을 수동으로 실행하면서 조정할 거라면 어떤 방언이든 출발점이 됩니다. 단, 무엇을 변경해야 하는지는 파악해 두세요.

타입 추론: 잘 되는 것과 실패하는 것

일반적인 케이스는 꽤 잘 처리합니다.

  • JSON의 123은 SQL에서 INT
  • 123.45FLOAT 또는 DECIMAL
  • "hello"VARCHAR(255) 또는 TEXT
  • true / falseBOOLEAN 또는 TINYINT(1)
  • null은 null 허용 컬럼, 보통 VARCHAR

문제가 생기는 건 JSON이 문자열로 비문자열 데이터를 표현할 때입니다.

전화번호가 대표적인 함정입니다. JSON에 "phone": "12345"가 있으면 JSON에서 문자열이니까 VARCHAR(255)가 됩니다. 전화번호는 문자열로 저장하는 게 맞으니까 이건 올바른 결과입니다. 하지만 소스 시스템이 전화번호를 정수로 저장했다면 "phone": 12345가 되고 INT로 타입이 잡힙니다. 그러면 임포트 시 앞자리 0과 서식이 사라집니다.

날짜 및 시간 필드는 거의 항상 VARCHAR로 나옵니다. JSON에는 네이티브 날짜 타입이 없기 때문입니다. "2025-01-15T09:23:00Z"는 JSON 입장에서는 그냥 문자열입니다. DATETIME이나 TIMESTAMP 컬럼이 필요하다면 생성 후 CREATE TABLE 구문에서 타입을 직접 바꾸세요. SQL이 TIMESTAMP 컬럼에 INSERT할 때 ISO 8601 문자열을 파싱해주기 때문에 데이터 자체는 문제없이 들어갑니다.

숫자처럼 보이는 ID도 까다롭습니다. id 필드 값이 1042INT로 타입이 잡힙니다. 괜찮을 수도 있지만, 시스템이 UUID나 영숫자 ID를 쓰는데 처음 몇 행이 우연히 전부 숫자일 수도 있습니다. 201번째 행의 id가 "a1b2c3"이라면 임포트가 실패합니다.

큰 텍스트 필드VARCHAR(255)로 타입이 잡힙니다. 필드에 기사 본문, 설명, 직렬화된 데이터처럼 긴 내용이 담긴다면, MySQL에서는 TEXT 또는 LONGTEXT, PostgreSQL에서는 길이 제한이 없는 TEXT로 바꿔야 합니다.

경험칙: 실행 전에 항상 생성된 CREATE TABLE 구문을 검토하세요. INSERT 구문은 보통 괜찮지만, 스키마 추론은 사람의 판단이 필요한 부분입니다.

일괄 INSERT: 왜 중요한가

데이터가 열 개나 스무 개라면 행마다 따로 INSERT해도 크게 상관없습니다. 데이터가 많아지면 차이가 커집니다.

행별 INSERT는 이런 모습입니다.

INSERT INTO `users` (`id`, `name`, `email`) VALUES (1, 'Alice', 'alice@example.com');
INSERT INTO `users` (`id`, `name`, `email`) VALUES (2, 'Ben', 'ben@example.com');
-- ... 198개 더

일괄 INSERT는 이런 모습입니다.

INSERT INTO `users` (`id`, `name`, `email`) VALUES
(1, 'Alice', 'alice@example.com'),
(2, 'Ben', 'ben@example.com'),
(3, 'Sara', 'sara@example.com'),
-- ... 최대 100행
;

INSERT INTO `users` (`id`, `name`, `email`) VALUES
(101, 'David', 'david@example.com'),
-- ... 다음 배치
;

일괄 방식이 빠른 이유는 두 가지입니다. 첫째, 행마다 한 번이 아니라 배치마다 한 번의 네트워크 왕복이 일어납니다. 둘째, 데이터베이스가 작은 쓰기 여러 번보다 큰 쓰기 한 번을 더 잘 최적화합니다. 트랜잭션 오버헤드, 인덱스 업데이트, WAL(Write-Ahead Logging)이 행마다가 아니라 구문마다 한 번씩 일어납니다.

변환기가 보통 100~500행씩 나누는 이유는 메모리와 안정성 때문입니다. 10,000행짜리 INSERT 구문 하나는 메모리 한계에 걸리거나, 파싱이 느리거나, 중간에 실패했을 때 어느 행이 문제인지 알기 어렵습니다. 작은 배치가 실용적입니다.

도구가 하지 못하는 것

한계를 명확히 알아야 나중에 디버깅에 시간을 낭비하지 않습니다.

외래 키 없음. 변환기는 테이블 간 관계를 모릅니다. JSON에 다른 테이블을 참조하는 user_id 필드가 있어도 그냥 INT 컬럼만 생깁니다. FOREIGN KEY 제약 조건이나 REFERENCES 절은 없습니다. 직접 추가해야 합니다.

인덱스 없음. 생성된 CREATE TABLE에는 인덱스 정의가 없습니다. 대용량 데이터를 임포트하고 쿼리할 거라면, 필터링이나 조인에 쓸 컬럼에 INDEX 또는 UNIQUE INDEX를 추가해야 합니다. 이건 항상 임포트 후 작업입니다.

기본 키 표시 없음. 도구가 id INT 컬럼을 만들 수 있지만 PRIMARY KEYAUTO_INCREMENT를 붙여주지는 않습니다. MySQL에서 id를 자동 증가 기본 키로 만들려면 컬럼 정의에 PRIMARY KEY AUTO_INCREMENT를 추가하거나, PostgreSQL에서는 SERIAL로 바꾸세요.

복잡한 타입이나 중첩 타입 불가. 필드 값이 객체("address": {"street": "123 Main St", "city": "Portland"})나 배열("tags": ["developer", "remote"])이면 관계형 스키마로 평탄화할 수 없습니다. 도구는 보통 JSON 문자열로 직렬화하거나 필드를 건너뜁니다. JSON 컬럼으로 저장하거나(MySQL 5.7+, PostgreSQL 지원), 별도의 컬럼으로 분리하거나, 별도 테이블로 정규화하는 방법 중 직접 선택해야 합니다.

업서트 로직 없음. 생성된 구문은 충돌 처리 없는 단순 INSERT입니다. 이미 데이터가 있는 테이블에 기본 키가 겹치는 데이터를 넣으면 제약 조건 위반 오류가 납니다. 멱등성 있는 임포트가 필요하다면 MySQL의 INSERT IGNORE, PostgreSQL의 ON CONFLICT DO NOTHING, SQL Server의 MERGE 중 하나를 직접 추가해야 합니다.

트랜잭션 없음. 출력이 BEGIN TRANSACTION / COMMIT으로 감싸져 있지 않습니다. 대용량 임포트에서는 전체를 트랜잭션으로 묶는 게 좋습니다. 중간에 실패하면 깔끔하게 롤백할 수 있습니다. 생성된 구문 앞뒤에 직접 추가하세요.

이 도구를 쓸 때 vs. 다른 방법을 쓸 때

JSON to SQL 변환기는 특정 상황에 딱 맞는 도구입니다. 모든 상황에 맞는 도구는 아닙니다.

이 도구를 쓰면 좋을 때:

  • 외부 소스에서 일회성 데이터 임포트가 필요할 때
  • 데이터베이스 간 데이터를 빠르게 이동해야 할 때
  • 데모나 테스트용 데이터베이스를 현실적인 데이터로 구성할 때
  • 애플리케이션 스택 없이 SQL로 직접 작업할 때
  • SQL 접근만 있는 사람에게 데이터를 공유해야 할 때

ORM이나 ETL 도구를 쓰는 게 나을 때:

  • 반복 가능하고 버전 관리되는 시드 데이터가 필요할 때 — Prisma의 db seed, Django의 fixtures, Rails의 seed 파일은 마이그레이션 워크플로와 통합되어 안전하게 재실행할 수 있습니다
  • 단순 삽입이 아니라 데이터 변환이 필요한 복잡한 임포트일 때
  • 관계와 외래 키 제약을 프로그래밍 방식으로 처리해야 할 때
  • 정기적으로 반복하는 작업일 때 — 파이썬과 sqlalchemy, dbt, Apache NiFi 같은 도구를 쓰는 게 낫습니다

JSON to SQL 변환기는 본질적으로 "이 데이터를 테이블에 넣어야 해"라는 상황을 위한 지름길입니다. 상황이 그보다 복잡하다면 더 복잡한 도구가 필요합니다.

실용적인 작업 흐름

잘 작동하는 순서는 이렇습니다.

  1. 먼저 JSON을 정리하세요. 내보낸 파일이 압축되어 있다면 JSON 포매터에 먼저 붙여넣어 구조를 확인하고 문제를 잡으세요.

  2. 배열 구조를 확인하세요. 변환기는 모든 객체가 동일한 최상위 키를 가진 JSON 배열을 기대합니다. 내보낸 파일이 배열이 아닌 루트 객체로 감싸져 있다면({"data": [...]}) 먼저 배열만 추출하세요.

  3. 방언을 선택하고 JSON을 붙여넣어 생성된 SQL을 복사하세요.

  4. CREATE TABLE을 검토하세요. 실행 전에 컬럼 타입을 읽고, 잘못 보이는 것을 고치세요. 특히 날짜 필드, 큰 텍스트 필드, 실제로는 문자열이어야 할 숫자 필드를 확인하세요.

  5. 필요한 제약 조건을 추가하세요. 기본 키 표시, 적절한 곳에 NOT NULL, 이메일 컬럼에 UNIQUE, 필요한 FOREIGN KEY 제약을 추가하세요.

  6. CREATE TABLE을 먼저 실행하고 그다음 INSERT를 실행하세요. 테이블이 이미 존재하고 재임포트한다면, 먼저 DROP TABLE IF EXISTS를 할지 충돌 처리 전략을 쓸지 결정하세요.

  7. 행 수를 확인하세요. 임포트 후 SELECT COUNT(*) FROM your_table;을 실행해 JSON의 행 수와 비교하세요. 일치하면 완료입니다.

출력 SQL 정리하기

생성된 SQL은 보통 읽기 쉽지만, 항상 원하는 스타일인 건 아닙니다. INSERT 구문을 일관성 있게 정리하고 싶다면 출력을 SQL 포매터에 통과시키세요. 의미는 바뀌지 않지만 검토하고 diff를 보기 훨씬 편해집니다.

정리

대용량 JSON 데이터셋에 INSERT 구문을 직접 작성하는 건 자동화가 가장 합리적인 작업 중 하나입니다. JSON to SQL 변환기는 기계적인 변환을 처리합니다. 배열을 읽고, 타입을 추론하고, 스키마를 생성하고, 대상 방언에 맞는 일괄 INSERT 구문을 만들어냅니다.

여전히 신경 써야 할 부분은 스키마 검토(타입, 제약, 인덱스), 중첩 데이터 처리, 그리고 재실행이 필요하다면 INSERT 로직의 멱등성입니다. 도구가 순전히 기계적인 90%를 처리합니다. 나머지 10%는 어떤 자동화도 대신할 수 없는 데이터베이스 설계 판단입니다.

JSON 데이터를 자주 다룬다면 이 도구와 함께 JSON 포매터SQL 포매터도 북마크해 두세요. 입력을 정리하고 생성된 출력을 마이그레이션 파일에 커밋하기 전에 다듬을 때 유용합니다.

자주 묻는 질문

D

작성자

Daniel Park

서울에서 활동하는 시니어 프런트엔드 엔지니어. 국내 SaaS 회사들에서 7년간 웹 애플리케이션을 개발하며 개발자 도구, 웹 성능 최적화, 프라이버시 중심 설계에 집중해 왔습니다. JavaScript 생태계 오픈소스 기여자이자 ToolPal 창립자입니다.

더 알아보기

이 글 공유하기

XLinkedIn

관련 글