키워드와 식별자
키워드와 식별자 (Keywords and Identifiers)
다른 SQL 방언과 프로그래밍 언어와 마찬가지로, DuckDB SQL의 식별자(identifier)에는 여러 규칙이 적용돼요.
출처: 문서
본문
식별자 (Identifiers)
- 따옴표 없는(unquoted) 식별자는 여러 규칙을 따라야 해요.
- 예약 키워드(reserved keyword)여선 안 돼요 (
duckdb_keywords()참고). 예:SELECT 123 AS SELECT는 실패해요. - 숫자나 특수 문자로 시작하면 안 돼요. 예:
SELECT 123 AS 1col은 유효하지 않아요. - 공백(탭과 줄바꿈 포함)을 포함할 수 없어요.
- 예약 키워드(reserved keyword)여선 안 돼요 (
- 식별자는 큰따옴표(
")로 감싸서 인용할 수 있어요. 인용된 식별자는 어떤 키워드, 공백, 특수 문자도 사용할 수 있어요. 예:"SELECT"와" § 🦆 ¶ "는 유효한 식별자예요. - 큰따옴표는 따옴표 문자를 반복해서 이스케이프할 수 있어요. 예:
IDENTIFIER "X"라는 식별자를 만들려면"IDENTIFIER ""X"""를 사용해요.
식별자 중복 제거 (Deduplicating Identifiers)
경우에 따라 중복 식별자가 발생할 수 있어요. 예를 들어 중첩 데이터 구조를 unnest할 때 컬럼 이름이 충돌할 수 있어요. 이런 경우 DuckDB는 다음 규칙에 따라 컬럼 이름을 다시 지정해 자동으로 중복을 제거해요.
⟨name⟩컬럼의 첫 번째 인스턴스는 이름을 바꾸지 않아요.- 이후 인스턴스는
⟨name⟩_⟨count⟩로 바꾸는데,⟨count⟩는 1부터 시작해요.
예를 들어:
SELECT *
FROM (SELECT unnest({'a': 42, 'b': {'a': 88, 'b': 99}}, recursive := true));
| a | a_1 | b |
|---|---|---|
| 42 | 88 | 99 |
데이터베이스 이름 (Database Names)
데이터베이스 이름은 식별자 규칙을 따르지만, 추가적으로 DuckDB의 두 내부 데이터베이스 스키마 이름, system과 temp를 피하는 것이 모범 사례예요. 기본적으로 영속 데이터베이스는 확장자를 뺀 파일 이름으로 이름 지어져요. 그래서 system.db와 temp.db(그리고 system.duckdb와 temp.duckdb) 파일 이름은 각각 system과 temp 데이터베이스 이름이 돼요. 이런 이름 중 하나를 가진 데이터베이스에 attach해야 한다면 별칭을 사용해요.
ATTACH 'temp.db' AS temp2;
USE temp2;
대소문자 규칙 (Rules for Case-Sensitivity)
키워드와 함수 이름 (Keywords and Function Names)
SQL 키워드와 함수 이름은 DuckDB에서 대소문자를 구분하지 않아요.
예를 들어 다음 두 쿼리는 동일해요.
select COS(Pi()) as CosineOfPi;
SELECT cos(pi()) AS CosineOfPi;
| CosineOfPi |
|---|
| -1.0 |
식별자의 대소문자 구분 (Case-Sensitivity of Identifiers)
DuckDB의 식별자는 PostgreSQL과 비슷하게 항상 대소문자를 구분하지 않아요. 그러나 PostgreSQL(그리고 일부 다른 주요 SQL 구현)과 달리 DuckDB는 인용된 식별자도 대소문자를 구분하지 않아요.
식별자 비교:
대소문자 비구분은 ASCII 기반 비교로 구현돼요.
col_A와 col_a는 같지만 col_á는 그것들과 같지 않아요.
SELECT col_A FROM (SELECT 'x' AS col_a); -- 성공
SELECT col_á FROM (SELECT 'x' AS col_a); -- 실패
대소문자 보존: DuckDB는 식별자를 대소문자 비구분으로 취급하지만, 식별자의 대소문자는 보존해요. 즉, 쿼리가 식별자를 참조할 때 다른 대소문자를 사용해도 각 문자의 대소문자(대문자/소문자)는 사용자가 원래 지정한 대로 유지돼요.
예를 들어:
CREATE TABLE tbl AS SELECT cos(pi()) AS CosineOfPi;
SELECT cosineofpi FROM tbl;
| CosineOfPi |
|---|
| -1.0 |
이 동작을 바꾸려면 preserve_identifier_case 설정 옵션을 false로 설정해요.
중첩 데이터 구조의 키 대소문자 구분 (Case-Sensitivity of Keys in Nested Data Structures)
MAP의 키는 대소문자를 구분해요.
SELECT MAP(['key1'], [1]) = MAP(['KEY1'], [1]) AS equal;
false
UNION과 STRUCT의 키는 대소문자를 구분하지 않아요.
SELECT {'key1': 1} = {'KEY1': 1} AS equal;
true
SELECT union_value(key1 := 1) = union_value(KEY1 := 1) as equal;
true
충돌 처리 (Handling Conflicts)
충돌 시, 같은 식별자가 다른 대소문자로 표기되면 하나가 무작위로 선택돼요. 예를 들어:
CREATE TABLE t1 (idfield INTEGER, x INTEGER);
CREATE TABLE t2 (IdField INTEGER, y INTEGER);
INSERT INTO t1 VALUES (1, 123);
INSERT INTO t2 VALUES (1, 456);
SELECT * FROM t1 NATURAL JOIN t2;
| idfield | x | y |
|---|---|---|
| 1 | 123 | 456 |
대소문자 보존 비활성화 (Disabling Preserving Cases)
preserve_identifier_case 설정 옵션을 false로 설정하면 모든 식별자가 소문자로 바뀌어요.
SET preserve_identifier_case = false;
CREATE TABLE tbl AS SELECT cos(pi()) AS CosineOfPi;
SELECT CosineOfPi FROM tbl;
| cosineofpi |
|---|
| -1.0 |