Friendly SQL
Friendly SQL
DuckDB는 SQL 쿼리를 더 간결하게 만들어주는 여러 고급 SQL 기능과 문법적 설탕(syntactic sugar)을 제공해요. 이를 흔히 "friendly SQL"이라고 부른답니다. SQL을 더 짧고 읽기 좋게 쓰고 싶다면 이 기능들을 눈여겨볼 만해요.
출처: 문서
본문
DuckDB는 SQL 쿼리를 더 간결하게 만들어주는 여러 고급 SQL 기능과 문법적 설탕을 제공해요. 우리는 이를 비공식적으로 "friendly SQL"이라고 불러요.
이 기능 중 몇몇은 DuckDB가 처음 도입했고, 일부는 다른 시스템에서 영감을 받았어요. DuckDB가 처음 도입한 많은 기능(예:
GROUP BY ALL)은 이후 다른 시스템들도 채택했어요.
팁 (Tip) 12개의 friendly SQL 기능에 대한 짧은 설명, 예시, 요약 일러스트가 담긴 Friendly SQL 2026 캘린더가 있어요.
절 (Clauses)
- 테이블 생성 및 데이터 삽입:
CREATE OR REPLACE TABLE: 스크립트에서DROP TABLE IF EXISTS문을 피할 수 있어요.CREATE TABLE ... AS SELECT(CTAS): 스키마를 수동으로 정의하지 않고 테이블의 출력으로 새 테이블을 만들어요.INSERT INTO ... BY NAME:INSERT문의 이 변형은 위치 대신 컬럼 이름을 사용할 수 있게 해줘요.INSERT OR IGNORE INTO ...:UNIQUE나PRIMARY KEY제약으로 인한 충돌이 없는 행을 삽입해요.INSERT OR REPLACE INTO ...:UNIQUE나PRIMARY KEY제약으로 인한 충돌이 없는 행을 삽입하고, 충돌하는 행은 기존 행의 컬럼을 삽입될 새 행의 값으로 교체해요.
- 테이블 설명 및 통계 계산:
- SQL 절을 더 압축하고 읽기 좋게 만들기:
FROM-first 문법(선택적SELECT절 포함): DuckDB는FROM tbl형태의 쿼리를 허용해서 모든 컬럼을 선택해요(SELECT *문 수행).GROUP BY ALL:SELECT절의 속성 목록에서 그룹-바이 컬럼을 추론해서 생략해요.ORDER BY ALL: 모든 컬럼에 정렬하는 단축 표기(예: 결정적 결과 보장).SELECT * EXCLUDE:EXCLUDE옵션은*표현식에서 특정 컬럼을 제외할 수 있게 해줘요.SELECT * REPLACE:REPLACE옵션은*표현식에서 특정 컬럼을 다른 표현식으로 교체할 수 있게 해줘요.UNION BY NAME: 위치에 의존하는 대신 컬럼 이름을 따라UNION연산을 수행해요.SELECT와FROM절에서 접두사 별칭: 가독성을 위해42 AS x대신x: 42을 써요.LIMIT절에서 테이블 크기의 백분율 지정:LIMIT 10%을 써서 쿼리 결과의 10%를 반환해요.
- 테이블 변환:
- SQL 수준 변수 정의:
쿼리 기능 (Query Features)
WHERE,GROUP BY,HAVING에서 컬럼 별칭. (참고: 컬럼 별칭은JOIN절의ON절에서는 사용할 수 없어요.)COLUMNS()표현식으로 여러 컬럼에 같은 표현식 실행하기:- 재사용 가능한 컬럼 별칭("lateral column aliases"라고도 함). 예:
SELECT i + 1 AS j, j + 2 AS k FROM range(0, 3) t(i) - 분석(OLAP) 쿼리를 위한 고급 집계 기능:
count(*)에 대한count()단축 표기- 리스트와 맵을 위한
IN연산자 - 공통 테이블 표현식(
WITH)에 대한 컬럼 이름 지정 JOIN절에서 컬럼 이름 지정JOIN절에서VALUES사용- 공통 테이블 표현식의 앵커 부분에서
VALUES사용 CASE표현식의 문법적 설탕으로서SWITCH문
리터럴과 식별자 (Literals and Identifiers)
데이터 타입 (Data Types)
데이터 가져오기 (Data Import)
- CSV 파일의 헤더와 스키마 자동 감지
- CSV 파일과 Parquet 파일 직접 쿼리
- 리플레이스먼트 스캔(Replacement scans):
FROM 'my.csv',FROM 'my.csv.gz',FROM 'my.parquet'등의 문법으로 파일에서 로드할 수 있어요.- Python에서는
FROM df로 Pandas 데이터 프레임에 접근할 수 있어요.
- 파일명 확장(globbing). 예:
FROM 'my-data/part-*.parquet'
함수와 표현식 (Functions and Expressions)
- 함수 체이닝을 위한 점(dot) 연산자:
SELECT ('hello').upper() - 문자열 포맷터:
fmt문법을 가진format()함수와printf()함수 - 리스트 컴프리헨션
- 리스트 슬라이싱과 뒤에서(
[-1]) 인덱싱 - 문자열 슬라이싱
STRUCT.*표기법- 대괄호로
LIST만들기 - 간단한
LIST와STRUCT생성 STRUCT의 스키마 업데이트
조인 타입 (Join Types)
트레일링 콤마 (Trailing Commas)
DuckDB는 트레일링 콤마를 허용해요.
엔티티 목록(예: 컬럼·테이블 이름)을 나열할 때나 LIST 항목을 구성할 때 모두요.
예를 들어 다음 쿼리는 작동해요:
SELECT
42 AS x,
['a', 'b', 'c',] AS y,
'hello world' AS z,
;
"그룹 내 Top-N" 쿼리 ("Top-N in Group" Queries)
일부 기준에 따라 정렬된 "그룹 내 top-N 행"을 계산하는 것은 SQL에서 흔한 작업인데, 불행히도 종종 윈도우 함수나 서브쿼리를 포함한 복잡한 쿼리가 필요해요.
이를 돕기 위해 DuckDB는 집계 함수 max(arg, n), min(arg, n), arg_max(arg, val, n), arg_min(arg, val, n), max_by(arg, val, n), min_by(arg, val, n)을 제공해서 특정 컬럼을 기준으로 오름차순 또는 내림차순으로 그룹의 "top" n 행을 효율적으로 반환해요.
예를 들어 다음 테이블을 사용해 보세요:
SELECT * FROM t1;
┌─────────┬───────┐
│ grp │ val │
│ varchar │ int32 │
├─────────┼───────┤
│ a │ 2 │
│ a │ 1 │
│ b │ 5 │
│ b │ 4 │
│ a │ 3 │
│ b │ 6 │
└─────────┴───────┘
각 그룹 grp에서 top-3 val 값의 목록을 얻고 싶다고 해요. 전통적인 방법은 서브쿼리에서 윈도우 함수를 사용하는 거예요:
SELECT array_agg(rs.val), rs.grp
FROM
(SELECT val, grp, row_number() OVER (PARTITION BY grp ORDER BY val DESC) AS rid
FROM t1 ORDER BY val DESC) AS rs
WHERE rid < 4
GROUP BY rs.grp;
┌───────────────────┬─────────┐
│ array_agg(rs.val) │ grp │
│ int32[] │ varchar │
├───────────────────┼─────────┤
│ [3, 2, 1] │ a │
│ [6, 5, 4] │ b │
└───────────────────┴─────────┘
하지만 DuckDB에서는 이걸 훨씬 더 간결하게(그리고 효율적으로!) 할 수 있어요:
SELECT max(val, 3) FROM t1 GROUP BY grp;
┌─────────────┐
│ max(val, 3) │
│ int32[] │
├─────────────┤
│ [3, 2, 1] │
│ [6, 5, 4] │
└─────────────┘
관련 블로그 글 (Related Blog Posts)
- "Friendlier SQL with DuckDB" 블로그 글
- "Even Friendlier SQL with DuckDB" 블로그 글
- "SQL Gymnastics: Bending SQL into Flexible New Shapes" 블로그 글
더 알아보기 (Learn more)
- GROUP BY ALL — 그룹핑 컬럼 자동 추론.
- FROM-first 문법 —
SELECT없이 쿼리하기.