SQL 포맷터

주요 SQL 방언(PostgreSQL / MySQL / Snowflake / T-SQL / BigQuery / SQLite 등)을 포맷합니다. 키워드 대소문자와 들여쓰기 설정을 조절할 수 있습니다.

Loading…

모든 처리는 브라우저 내부에서 실행됩니다 — 파일·입력은 서버로 전송되지 않습니다.

사용법

왼쪽에 SQL문을 붙여 넣으면 오른쪽 패널에 절마다 한 줄, JOIN을 세로로 정렬, 리스트를 줄바꿈으로 나눈 가독성 좋은 형태로 출력됩니다. Dialect 셀렉터로 대상 DB(PostgreSQL·MySQL·Snowflake·T-SQL·BigQuery·SQLite 외 총 14종)에 맞추세요. 방언 선택은 예약어 인식, 인용 식별자 처리, `QUALIFY`·`RETURNING`·`EXCEPT` 같은 방언별 절의 해석에 영향을 줍니다. Keyword case는 UPPER(SQL커뮤니티 관례), lower, preserve 중 선택할 수 있고 tab width는 1~8 스페이스로 조절합니다.

포맷터는 문장을 절 트리로 파싱한 뒤 다시 출력합니다. 정규식 기반 프리티프린터가 아니므로 JOIN 사이의 콤마나 인라인 CASE 식이 그냥 줄바꿈되는 것이 아니라 구조를 유지한 채 정렬됩니다. 스키마에 대한 쿼리 검증이나 쿼리 실행은 하지 않습니다. 모든 처리는 `sql-formatter` 라이브러리를 사용해 브라우저 안에서 끝나므로 내부 테이블명이나 운영 데이터가 포함된 쿼리도 기기 밖으로 나가지 않습니다.

예제

한 줄로 적힌 즉석 쿼리 정리

입력
select id, name, email from users where created_at > '2024-01-01' and status in ('active','pending') order by created_at desc limit 100
출력
SELECT
  id,
  name,
  email
FROM
  users
WHERE
  created_at > '2024-01-01'
  AND status IN ('active', 'pending')
ORDER BY
  created_at DESC
LIMIT
  100

각 절이 독립된 헤더 줄이 되고 컬럼 리스트는 한 줄에 한 컬럼으로 분리됩니다. 컬럼을 추가하거나 순서를 바꿨을 때 diff가 깔끔하므로 한 줄 쿼리보다 PR에서 변경 지점을 잡기 쉬워집니다.

CTE와 JOIN이 얽힌 복잡한 쿼리 정렬(PostgreSQL)

입력
with active_users as (select id from users where status='active') select o.id, o.total, u.email from orders o join active_users au on o.user_id=au.id join users u on u.id=au.id where o.created_at >= now() - interval '7 days' returning *
출력
WITH active_users AS (
  SELECT
    id
  FROM
    users
  WHERE
    status = 'active'
)
SELECT
  o.id,
  o.total,
  u.email
FROM
  orders o
  JOIN active_users au ON o.user_id = au.id
  JOIN users u ON u.id = au.id
WHERE
  o.created_at >= now() - INTERVAL '7 days'
RETURNING
  *

CTE 본문은 들여쓰기로 중첩되고 JOIN은 FROM 아래에 세로로 정렬되며 조건은 인라인으로 표시됩니다. `RETURNING`과 `INTERVAL '7 days'` 구문이 있어 PostgreSQL 방언을 골라야 합니다. Standard SQL 모드는 이를 인식하지 못합니다.

방언 불일치 — 잘못된 선택이 파싱을 망가뜨리는 예

입력
SELECT * FROM events QUALIFY ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY ts DESC) = 1
출력
(parses cleanly with Snowflake or BigQuery dialect; loses structure with PostgreSQL since it has no QUALIFY clause)

`QUALIFY`는 윈도 함수 이후에 행을 거르는 절로 Snowflake·BigQuery·Databricks·Teradata에 존재하지만 PostgreSQL·MySQL·SQLite에는 없습니다. 해당 방언을 골라야 하며, 그렇지 않으면 포맷터가 `QUALIFY`를 알 수 없는 식별자로 인식해 구조가 약한 출력으로 떨어집니다.

자주 묻는 질문

포맷터가 쿼리를 실행하거나 검증하나요?

아니요. 구문을 다시 출력할 뿐입니다. 파서가 토큰이 인식 가능한 형태인지는 확인하지만, 데이터베이스에 연결하거나 테이블을 조회하거나 컬럼 존재를 확인하지는 않습니다. 이 도구에서 깔끔히 정렬된 쿼리도 테이블명 오타, 권한 부족, 스키마 변경 등으로 실행 시 실패할 수 있습니다.

키워드는 왜 기본이 대문자인가요?

SQL커뮤니티의 오랜 관례입니다. 예약어를 대문자로 두면 구문 하이라이트가 없는 터미널이나 grep 출력에서도 절 구조가 소문자 식별자와 대비되어 잘 보입니다. Mode·Holistics·SQL Style Guide의 가이드라인도 한결같이 권장합니다. 팀이 Python식 소문자를 선호하면 `lower`, 입력을 그대로 두고 싶으면 `preserve`로 전환하세요.

방언이 헷갈리면 어느 것을 골라야 하나요?

쿼리가 실행될 데이터베이스에 맞추세요. 모르겠다면 PostgreSQL이 가장 무난한 중간 선택입니다. Standard SQL의 넓은 상위 호환(윈도 함수·CTE·`RETURNING`·JSON 연산자 등)을 받아들이고, 다른 엔진을 위해 작성된 쿼리도 대부분 무리 없이 파싱됩니다. BigQuery·Snowflake·T-SQL이라면 방언별 절(`QUALIFY`·차집합의 `EXCEPT`·`TOP n` 등)이 매칭되는 파서를 요구하므로 명시적으로 그쪽을 골라야 합니다.

탭이 비활성화되어 있는데 `\t` 들여쓰기로 출력할 수 없나요?

대부분의 코드 리뷰 도구·diff 뷰어·공유 환경이 탭을 예측 불가하게 표시하기 때문에(어떤 에디터는 4 스페이스, 다른 에디터는 8 스페이스 등) 이 도구는 스페이스를 강제합니다. 스타일 가이드가 탭을 요구하면 출력을 `expand -t1 | sed 's/ /\t/g'`로 후처리하거나 에디터의 일괄 치환으로 탭으로 되돌리세요. 실운영 SQL 파일은 거의 예외 없이 스페이스를 씁니다.

쿼리 안의 주석은 유지되나요?

네. 라인 주석(`--`)과 블록 주석(`/* … */`) 모두 원래 위치에 보존됩니다. 파싱·재출력 왕복에서도 사라지지 않으므로 운영 쿼리에 그대로 포맷터를 돌려도 인라인 문서가 손실되지 않습니다. `/*+ INDEX(t i_t_a) */`(Oracle)나 `/*! STRAIGHT_JOIN */`(MySQL) 같은 힌트 구문도 일반 주석 블록으로 유지됩니다.

에디터의 format-on-save에는 이 도구와 CLI 중 어느 쪽이 좋나요?

에디터 통합에는 CLI를 쓰세요. `pg_format`, `sqlfluff format`, 또는 `sql-formatter` 패키지 자체를 Prettier 플러그인으로 호출하는 방법이 있습니다. 이 웹 도구는 단발성 붙여 넣기를 위한 것입니다(동료의 즉석 쿼리, 스크린샷에서 옮겨 쓴 쿼리, 티켓 생성 전 확인 등 10줄 정렬을 위해 프로젝트를 열기 과한 경우). 두 쪽은 같은 포맷팅 라이브러리를 공유하므로 출력 결과에 차이가 없습니다.

관련 개념

SQL은 1986년에 처음 표준화되었고(ANSI SQL-86) 현행 버전은 SQL:2023이지만, 주요 엔진은 모두 표준 위에 자기 방언을 얹습니다. 차이는 표면적이지 않습니다. Snowflake에서 동작하는 쿼리가 PostgreSQL에서는 파싱되지 않는 이유는 `QUALIFY`·`LATERAL FLATTEN`·`:` 변수 치환 같은 것 때문입니다. `GO` 구분자와 `DECLARE @x`가 들어간 T-SQL 배치는 MySQL에서는 의미가 없습니다. 방언 인식 포맷터는 선택된 문법에 대해 쿼리를 파싱한 뒤, 표준에 없는 구문도 보존한 채 재출력합니다.

포맷팅은 인접한 세 분야 중 하나입니다. **포맷팅**은 쿼리 의미를 바꾸지 않고 공백과 대소문자만 재구성합니다(이 도구). **린팅**은 스타일이나 정확성의 냄새를 짚어 냅니다(`sqlfluff`·`sqlint`·Snowflake용 `dbt` linter 등). 한정되지 않은 `*`, 사용되지 않는 CTE, 암묵 형변환 같은 것들입니다. **정적 분석**은 한 발 더 나가(`squawk`·`eversql`·`pganalyze`) 쿼리 플랜을 읽고 인덱스 부족이나 테이블 잠금 DDL을 경고합니다. 포맷터는 커밋마다 안전하게 자동 실행할 수 있습니다. 린터는 pre-commit 훅에 적합하고, 분석기는 보통 실제 플래너를 상대로 실행합니다.

인접한 SQL 작성 관행 3가지도 알아 둘 만합니다. **선두 콤마**(`column_a,` 대신 `, column_a`를 두는 방식)는 행 추가 시 diff를 깔끔하게 만들며 Mode·HashiCorp·일부 데이터팀 스타일 가이드가 채택합니다. `sql-formatter`는 이를 강제하지 않습니다. **강형 포맷팅**(river formatting)은 절 키워드(`SELECT`·`FROM`·`WHERE` 등)를 공통 열에 오른쪽 정렬로 배치합니다. 옛 Oracle 계열 현장에서 보였고, 유지 관리가 어려워 현대 가이드 대부분이 권장하지 않습니다. **스택 포맷팅**은 이 도구의 기본값으로, 절 헤더를 독립된 줄에 두고 내용을 아래로 들여 씁니다. 팀이 풀 리퀘스트에서 가장 빨리 읽는 형식을 고르고 포맷터에 통제를 맡기는 편이 현실적입니다.

관련 도구