이 장에서는 SQL 문법의 기본 개념을 설명한다. 이는 데이터를 정의하고 수정하는 SQL 명령어를 다루는 이후 장들의 기초가 된다.
SQL에 이미 익숙한 독자들도 이 장을 주의 깊게 읽을 것을 권장한다. 여러 SQL 데이터베이스에서 일관되지 않게 구현된 규칙과 개념들, 그리고 PostgreSQL만의 고유한 특징을 자세히 다루기 때문이다.
SQL 입력은 일련의 *커맨드*로 구성된다. 하나의 커맨드는 여러 개의 *토큰*을 순서대로 나열하고 세미콜론(“;”)으로 끝맺는다. 입력 스트림의 끝에 도달해도 커맨드가 종료된다. 어떤 토큰이 유효한지는 해당 커맨드의 문법에 따라 결정된다.
토큰은 키워드, 식별자, 따옴표로 묶인 식별자, 리터럴(또는 상수), 또는 특수 문자 기호가 될 수 있다. 토큰은 일반적으로 공백(스페이스, 탭, 줄바꿈)으로 구분하지만, 모호하지 않은 경우에는 공백 없이도 사용할 수 있다. 이는 주로 특수 문자가 다른 종류의 토큰과 인접해 있을 때 가능하다.
예를 들어, 다음은 문법적으로 유효한 SQL 입력이다:
SELECT * FROM MY_TABLE;
UPDATE MY_TABLE SET A = 5;
INSERT INTO MY_TABLE VALUES (3, 'hi there');
이는 세 개의 커맨드를 한 줄씩 나열한 것이다. 반드시 이렇게 작성할 필요는 없다. 한 줄에 여러 커맨드를 작성할 수도 있고, 하나의 커맨드를 여러 줄에 걸쳐 작성하는 것도 가능하다.
또한 SQL 입력에는 *주석*을 포함할 수 있다. 주석은 토큰으로 간주하지 않으며, 실질적으로 공백과 동일한 역할을 한다.
SQL 문법은 어떤 토큰이 커맨드를 식별하고 어떤 것이 피연산자나 매개변수인지 구분하는 규칙이 완벽하게 일관적이지는 않다. 일반적으로 처음 몇 개의 토큰이 커맨드 이름을 나타내므로, 위 예제에서는 “SELECT”, “UPDATE”, “INSERT” 커맨드라고 부른다. 하지만 UPDATE
커맨드는 반드시 특정 위치에 SET
토큰이 있어야 하며, 이 특정 형태의 INSERT
는 완성을 위해 VALUES
가 필요하다. 각 커맨드의 정확한 문법 규칙은 제6부에서 자세히 설명한다.
위 예제에서 SELECT
, UPDATE
, VALUES
와 같은 토큰은 *키워드*의 예시다. 이는 SQL 언어에서 고정된 의미를 갖는 단어를 말한다. MY_TABLE
과 A
와 같은 토큰은 *식별자*의 예시다. 식별자는 사용되는 명령에 따라 테이블, 컬럼 또는 다른 데이터베이스 객체의 이름을 구분한다. 따라서 간단히 “이름”이라고도 부른다. 키워드와 식별자는 동일한 어휘 구조를 가지므로, 언어를 이해하지 않고는 특정 토큰이 식별자인지 키워드인지 구분할 수 없다. 키워드의 전체 목록은 부록 C에서 확인할 수 있다.
SQL 식별자와 키워드는 반드시 문자(a
-z
, 발음 구별 기호가 있는 문자와 비 라틴 문자 포함) 또는 밑줄(_
)로 시작해야 한다. 식별자나 키워드의 후속 문자로는 문자, 밑줄, 숫자(0
-9
), 달러 기호($
)를 사용할 수 있다. SQL 표준에 따르면 식별자에 달러 기호를 사용할 수 없으므로, 이를 사용하면 애플리케이션의 이식성이 떨어질 수 있다. SQL 표준은 숫자를 포함하거나 밑줄로 시작하거나 끝나는 키워드를 정의하지 않으므로, 이러한 형식의 식별자는 향후 표준이 확장되더라도 충돌하지 않는다.
시스템은 식별자의 길이를 NAMEDATALEN
-1 바이트로 제한한다. 명령에서는 더 긴 이름을 작성할 수 있지만 이는 잘린다. 기본적으로 NAMEDATALEN
은 64이므로 최대 식별자 길이는 63바이트다. 이 제한이 문제가 된다면 src/include/pg_config_manual.h
의 NAMEDATALEN
상수를 변경하여 늘릴 수 있다.
키워드와 따옴표로 묶지 않은 식별자는 대소문자를 구분하지 않는다. 따라서:
UPDATE MY_TABLE SET A = 5;
는 다음과 같이 작성할 수 있다:
uPDaTE my_TabLE SeT a = 5;
일반적으로 키워드는 대문자로, 이름은 소문자로 작성하는 관례가 있다:
UPDATE my_table SET a = 5;
두 번째 종류의 식별자로는 구분된 식별자 또는 *따옴표로 묶인 식별자*가 있다. 이는 임의의 문자열을 이중 따옴표("
)로 묶어 형성한다. 구분된 식별자는 항상 식별자이며 절대 키워드가 될 수 없다. 따라서 "select"
는 “select”라는 이름의 컬럼이나 테이블을 참조할 수 있지만, 따옴표로 묶지 않은 select
는 키워드로 해석되어 테이블이나 컬럼 이름이 필요한 위치에서 사용하면 구문 오류가 발생한다. 예제는 다음과 같이 따옴표로 묶인 식별자를 사용하여 작성할 수 있다:
UPDATE "my_table" SET "a" = 5;
따옴표로 묶인 식별자는 코드값이 0인 문자를 제외한 모든 문자를 포함할 수 있다. (이중 따옴표를 포함하려면 이중 따옴표를 두 번 작성한다.) 이를 통해 공백이나 앰퍼샌드(&)를 포함하는 등 일반적으로는 불가능한 테이블이나 컬럼 이름을 만들 수 있다. 길이 제한은 여전히 적용된다.
식별자를 따옴표로 묶으면 대소문자를 구분하게 되지만, 따옴표로 묶지 않은 이름은 항상 소문자로 변환된다. 예를 들어, PostgreSQL은 FOO
, foo
, "foo"
를 동일하게 간주하지만, "Foo"
와 "FOO"
는 이 세 가지와도 서로와도 다르다. (PostgreSQL에서 따옴표로 묶지 않은 이름을 소문자로 변환하는 것은 SQL 표준과 맞지 않는다. 표준에 따르면 따옴표로 묶지 않은 이름은 대문자로 변환되어야 한다. 따라서 표준에 따르면 foo
는 "FOO"
와 동등해야 하며 "foo"
와 동등해서는 안 된다. 이식 가능한 애플리케이션을 작성하려면 특정 이름을 항상 따옴표로 묶거나 절대 묶지 않는 것이 좋다.)
따옴표로 묶인 식별자의 변형으로, 코드 포인트로 식별된 이스케이프된 유니코드 문자를 포함할 수 있다. 이 변형은 열린 이중 따옴표 바로 앞에 U&
(대문자 또는 소문자 U와 앰퍼샌드)로 시작한다. 예를 들어 U&"foo"
와 같다. (이는 연산자 &
와 모호성을 만든다. 이 문제를 피하려면 연산자 주변에 공백을 사용한다.) 따옴표 안에서 유니코드 문자는 역슬래시 뒤에 4자리 16진수 코드 포인트 번호를 작성하거나, 역슬래시와 더하기 기호 뒤에 6자리 16진수 코드 포인트 번호를 작성하여 이스케이프 형식으로 지정할 수 있다. 예를 들어 식별자 "data"
는 다음과 같이 작성할 수 있다:
U&"d0061t+000061"
다음은 더 복잡한 예시로, 키릴 문자로 러시아어 단어 “slon”(코끼리)을 작성한다:
U&"0441043B043E043D"
역슬래시 대신 다른 이스케이프 문자를 사용하려면 문자열 뒤에 UESCAPE
절을 사용하여 지정할 수 있다:
U&"d!0061t!+000061" UESCAPE '!'
이스케이프 문자는 16진수 숫자, 더하기 기호, 작은따옴표, 큰따옴표, 공백 문자를 제외한 모든 단일 문자가 될 수 있다. UESCAPE
뒤의 이스케이프 문자는 이중 따옴표가 아닌 작은따옴표로 작성된다.
식별자에 이스케이프 문자를 문자 그대로 포함하려면 두 번 작성한다.
U+FFFF보다 큰 코드 포인트를 가진 문자를 구성하기 위해 UTF-16 서로게이트 쌍을 지정할 때는 4자리 또는 6자리 이스케이프 형식을 사용할 수 있다. 6자리 형식을 사용할 수 있으므로 기술적으로는 4자리 형식이 불필요하다. (서로게이트 쌍은 직접 저장되지 않고 단일 코드 포인트로 결합된다.)
서버 인코딩이 UTF-8이 아닌 경우, 이스케이프 시퀀스로 식별된 유니코드 코드 포인트는 실제 서버 인코딩으로 변환된다. 변환이 불가능한 경우 오류가 보고된다.
PostgreSQL은 세 가지 종류의 *암시적 타입 상수(implicitly-typed constants)*를 지원한다. 문자열, 비트 문자열, 숫자가 이에 해당한다. 또한 명시적 타입을 사용해 상수를 선언할 수도 있는데, 이는 시스템이 더 정확하게 값을 표현하고 효율적으로 처리하는 데 도움이 된다. 이러한 다양한 상수 선언 방식에 대해서는 다음 하위 섹션에서 자세히 다룬다.
SQL의 문자열 상수는 작은따옴표('
)로 둘러싸인 임의의 문자 시퀀스다. 예를 들어 'This is a string'
와 같은 형태로 표현한다. 문자열 상수 안에 작은따옴표를 포함하려면 작은따옴표를 연속해서 두 번 입력해야 한다. 예를 들어 'Dianne''s horse'
와 같이 표현한다. 이때 연속된 작은따옴표는 큰따옴표("
)와 다르다는 점에 주의한다.
공백으로만 구분된 두 문자열 상수 사이에 *최소 한 개의 줄바꿈*이 있다면, 이 두 문자열은 하나의 상수로 연결되어 처리된다. 예를 들면 다음과 같다:
SELECT 'foo'
'bar';
이 구문은 다음과 동일하다:
SELECT 'foobar';
하지만 다음 구문은 유효하지 않다:
SELECT 'foo' 'bar';
이런 특이한 동작은 SQL 표준에 명시된 것으로, PostgreSQL은 이 표준을 그대로 따르고 있다.
PostgreSQL은 SQL 표준을 확장한 “이스케이프” 문자열 상수도 지원한다. 이스케이프 문자열 상수는 여는 작은따옴표 바로 앞에 문자 E
(대소문자 구분 없음)를 붙여서 지정한다. 예를 들어 E'foo'
와 같이 작성한다. 이스케이프 문자열 상수를 여러 줄에 걸쳐 계속 작성할 때는 첫 번째 여는 따옴표 앞에만 E
를 붙이면 된다. 이스케이프 문자열 내에서 백슬래시 문자(\
)는 C 언어와 유사한 백슬래시 이스케이프 시퀀스를 시작하며, 백슬래시와 그 뒤에 오는 문자의 조합이 특별한 바이트 값을 나타낸다. 표 4.1에서 자세한 내용을 확인할 수 있다.
표 4.1. 백슬래시 이스케이프 시퀀스
백슬래시 이스케이프 시퀀스 | 해석 |
---|---|
\b | 백스페이스 |
\f | 폼 피드 |
\n | 줄바꿈 |
\r | 캐리지 리턴 |
\t | 탭 |
\o, \oo, \ooo (o = 0-7) | 8진수 바이트 값 |
\xh, \xhh (h = 0-9, A-F) | 16진수 바이트 값 |
\uxxxx, \Uxxxxxxxx (x = 0-9, A-F) | 16비트 또는 32비트 16진수 유니코드 문자 값 |
백슬래시 다음에 오는 다른 모든 문자는 문자 그대로 해석된다. 따라서 백슬래시 문자를 포함하려면 두 개의 백슬래시(\\
)를 작성해야 한다. 또한 작은따옴표를 이스케이프 문자열에 포함할 때는 일반적인 방법인 ''
외에도 \'
를 사용할 수 있다.
개발자는 특히 8진수나 16진수 이스케이프를 사용할 때 서버의 문자 집합 인코딩에서 유효한 문자를 구성하는 바이트 시퀀스를 만들어야 할 책임이 있다. 이에 대한 유용한 대안으로 4.1.2.3절에서 설명하는 유니코드 이스케이프나 대체 유니코드 이스케이프 문법을 사용할 수 있다. 이 방법을 사용하면 서버가 문자 변환이 가능한지 검사한다.
설정 매개변수 standard_conforming_strings가 off
로 설정된 경우, PostgreSQL은 일반 문자열 상수와 이스케이프 문자열 상수 모두에서 백슬래시 이스케이프를 인식한다. 하지만 PostgreSQL 9.1부터 기본값은 on
이며, 이는 백슬래시 이스케이프를 이스케이프 문자열 상수에서만 인식한다는 의미다. 이 동작은 표준을 더 잘 준수하지만, 백슬래시 이스케이프를 항상 인식하던 과거 동작에 의존하는 애플리케이션에 문제를 일으킬 수 있다. 임시 해결책으로 이 매개변수를 off
로 설정할 수 있지만, 백슬래시 이스케이프 사용을 중단하는 것이 더 바람직하다. 특수 문자를 나타내기 위해 백슬래시 이스케이프를 사용해야 한다면, 문자열 상수 앞에 E
를 붙여 작성한다.
standard_conforming_strings
외에도 escape_string_warning과 backslash_quote 설정 매개변수가 문자열 상수에서 백슬래시 처리 방식을 결정한다.
문자열 상수에는 코드값이 0인 문자를 포함할 수 없다.
PostgreSQL은 유니코드 코드 포인트를 사용하여 임의의 유니코드 문자를 지정할 수 있는 또 다른 이스케이프 문법을 지원한다. 유니코드 이스케이프 문자열 상수는 따옴표 바로 앞에 U&
(대문자 또는 소문자 U와 앰퍼샌드)로 시작한다. 이때 사이에 공백이 있으면 안 된다. 예를 들어 U&'foo'
와 같은 형식이다. (이는 연산자 &
와 혼동될 수 있으므로, 연산자 주위에 공백을 넣어 이 문제를 피할 수 있다.)
따옴표 안에서 유니코드 문자는 백슬래시 뒤에 4자리 16진수 코드 포인트 번호를 붙이거나, 백슬래시와 더하기 기호 뒤에 6자리 16진수 코드 포인트 번호를 붙여 이스케이프 형식으로 지정할 수 있다. 예를 들어, 'data'
문자열은 다음과 같이 작성할 수 있다:
U&'d\0061t\+000061'
다음은 좀 더 복잡한 예제로, 러시아어 단어 “slon”(코끼리)을 키릴 문자로 작성한다:
U&'\0441\043B\043E\043D'
백슬래시 대신 다른 이스케이프 문자를 사용하고 싶다면, 문자열 뒤에 UESCAPE
절을 사용하여 지정할 수 있다. 예를 들면:
U&'d!0061t!+000061' UESCAPE '!'
이스케이프 문자는 16진수 숫자, 더하기 기호, 작은따옴표, 큰따옴표, 공백 문자를 제외한 어떤 단일 문자도 사용할 수 있다. 문자열 안에 이스케이프 문자 자체를 포함하려면 해당 문자를 두 번 연속해서 작성한다.
U+FFFF보다 큰 코드 포인트를 가진 문자를 만들기 위해 UTF-16 서로게이트 쌍을 지정할 때는 4자리 또는 6자리 이스케이프 형식을 모두 사용할 수 있다. 6자리 형식이 있으므로 기술적으로는 서로게이트 쌍이 불필요하지만, 지원은 된다. (서로게이트 쌍은 직접 저장되지 않고 단일 코드 포인트로 결합된다.)
서버 인코딩이 UTF-8이 아닌 경우, 이스케이프 시퀀스로 식별된 유니코드 코드 포인트는 실제 서버 인코딩으로 변환된다. 변환이 불가능한 경우 오류가 발생한다.
문자열 상수에 대한 유니코드 이스케이프 문법은 설정 매개변수 standard_conforming_strings가 켜져 있을 때만 작동한다. 이는 이 문법이 SQL 구문을 분석하는 클라이언트에게 혼란을 주어 SQL 인젝션과 같은 보안 문제를 일으킬 수 있기 때문이다. 이 매개변수가 꺼져 있으면 오류 메시지와 함께 이 문법은 거부된다.
표준 문자열 상수 문법은 대체로 편리하지만, 문자열 내에 작은따옴표가 많이 포함된 경우 각각을 두 번씩 입력해야 하므로 가독성이 떨어진다. PostgreSQL은 이러한 상황에서 쿼리를 더 쉽게 읽을 수 있도록 “달러 인용”이라는 다른 방식의 문자열 상수 작성법을 제공한다.
달러 인용 문자열 상수는 다음과 같은 구조로 구성된다:
- 달러 기호($
)로 시작
- 선택적으로 0개 이상의 문자로 구성된 “태그” 추가
- 다시 달러 기호
- 문자열 내용을 구성하는 임의의 문자열
- 달러 기호
- 시작할 때 사용한 것과 동일한 태그
- 마지막으로 달러 기호
예를 들어, “Dianne’s horse”라는 문자열을 달러 인용을 사용해 다음과 같이 두 가지 방식으로 표현할 수 있다:
$$Dianne's horse$$
$SomeTag$Dianne's horse$SomeTag$
달러 인용 문자열 내부에서는 작은따옴표를 이스케이프 처리할 필요가 없다. 실제로 달러 인용 문자열 내부의 어떤 문자도 이스케이프 처리되지 않으며, 문자열 내용은 항상 그대로 해석된다. 백슬래시나 달러 기호도 특별한 의미를 가지지 않는다. 단, 시작 태그와 일치하는 시퀀스의 일부인 경우는 예외다.
서로 다른 태그를 선택하면 달러 인용 문자열 상수를 중첩할 수 있다. 이는 주로 함수 정의를 작성할 때 사용한다. 예를 들면:
$function$
BEGIN
RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
END;
$function$
이 예제에서 $q$[\t\r\n\v\\]$q$
시퀀스는 달러 인용 리터럴 문자열 [\t\r\n\v\\]
을 나타낸다. PostgreSQL이 함수 본문을 실행할 때 이 문자열을 인식한다. 하지만 이 시퀀스는 외부 달러 인용 구분자인 $function$
과 일치하지 않으므로, 외부 문자열의 관점에서는 단순히 문자열의 일부로 취급된다.
태그는 달러 기호를 포함할 수 없다는 점을 제외하면 따옴표 없는 식별자와 동일한 규칙을 따른다. 태그는 대소문자를 구분한다. 따라서 $tag$String content$tag$
는 올바르지만 $TAG$String content$tag$
는 올바르지 않다.
키워드나 식별자 뒤에 오는 달러 인용 문자열은 공백으로 구분해야 한다. 그렇지 않으면 달러 인용 구분자가 앞의 식별자의 일부로 해석된다.
달러 인용은 SQL 표준의 일부는 아니지만, 복잡한 문자열 리터럴을 작성할 때 표준을 준수하는 작은따옴표 문법보다 더 편리하다. 특히 프로시저 함수 정의에서 자주 필요한 것처럼, 다른 상수 안에 문자열 상수를 표현할 때 유용하다. 작은따옴표 문법을 사용할 경우, 위 예제의 각 백슬래시는 네 개의 백슬래시로 작성해야 하며, 이는 원래 문자열 상수를 구문 분석할 때 두 개로 줄어들고, 함수 실행 중에 내부 문자열 상수를 다시 구문 분석할 때 하나로 줄어든다.
비트열 상수는 일반 문자열 상수와 비슷하지만, 따옴표 바로 앞에 B
(대문자 또는 소문자)를 붙여 표현한다. 이때 B
와 따옴표 사이에는 공백이 들어갈 수 없다. 예를 들어 B'1001'
과 같이 작성한다. 비트열 상수 안에는 오직 0
과 1
만 사용할 수 있다.
또 다른 방법으로, 비트열 상수를 16진수로 표현할 수도 있다. 이 경우에는 앞에 X
(대문자 또는 소문자)를 붙인다. 예를 들어 X'1FF'
와 같이 작성한다. 16진수로 표현한 비트열 상수는 각 16진수 숫자당 4개의 2진수 숫자로 변환된다는 점에서 일반 비트열 상수와 동일한 의미를 갖는다.
두 형태의 비트열 상수 모두 일반 문자열 상수처럼 여러 줄에 걸쳐 작성할 수 있다. 단, 비트열 상수에서는 달러 표시를 사용한 인용 방식을 사용할 수 없다.
숫자형 상수는 다음과 같은 기본 형식을 사용한다:
digits
digits.[digits][e[+-]digits]
[digits].digits[e[+-]digits]
digitse[+-]digits
여기서 digits
는 하나 이상의 십진수(0부터 9)를 의미한다. 소수점을 사용할 경우 소수점 앞이나 뒤에 최소 한 자리의 숫자가 필요하다. 지수 표기(e
)를 사용할 경우에도 그 뒤에 반드시 한 자리 이상의 숫자가 있어야 한다. 숫자형 상수 안에는 시각적 구분을 위한 밑줄 외의 다른 문자나 공백을 포함할 수 없다. 선행하는 더하기나 빼기 기호는 상수의 일부가 아닌 상수에 적용되는 연산자로 취급한다.
유효한 숫자형 상수의 예시는 다음과 같다:
42
3.5
4.
.001
5e2
1.925e-3
추가로, 비십진수 정수 상수는 다음 형식으로 표현할 수 있다:
0xhexdigits
0ooctdigits
0bbindigits
여기서 hexdigits
는 하나 이상의 16진수(0-9, A-F), octdigits
는 하나 이상의 8진수(0-7), bindigits
는 하나 이상의 2진수(0 또는 1)를 의미한다. 16진수와 기수 접두사는 대소문자를 구분하지 않는다. 비십진수 형식은 정수에만 사용할 수 있으며, 소수부가 있는 숫자에는 사용할 수 없다.
유효한 비십진수 정수 상수의 예시는 다음과 같다:
0b100101
0B10011001
0o273
0O755
0x42f
0XFFFF
시각적 구분을 위해 숫자 사이에 밑줄을 넣을 수 있다. 이는 상수의 값에 영향을 주지 않는다. 예시:
1_500_000_000
0b10001000_00000000
0o_1_755
0xFFFF_FFFF
1.618_034
밑줄은 숫자형 상수의 시작이나 끝, 숫자 그룹의 시작이나 끝(소수점이나 지수 표기 바로 앞뒤)에 사용할 수 없으며, 연속해서 사용할 수 없다.
소수점이나 지수가 없는 숫자형 상수는 처음에 integer
타입(32비트)에 맞으면 integer
로 간주하고, 그렇지 않으면서 bigint
타입(64비트)에 맞으면 bigint
로 간주하며, 둘 다 아니면 numeric
타입으로 취급한다. 소수점이나 지수를 포함하는 상수는 항상 처음에 numeric
타입으로 간주한다.
숫자형 상수에 처음 할당되는 데이터 타입은 타입 결정 알고리즘의 시작점일 뿐이다. 대부분의 경우 문맥에 따라 가장 적절한 타입으로 자동 변환된다. 필요한 경우 캐스팅을 통해 숫자값을 특정 데이터 타입으로 강제 해석할 수 있다. 예를 들어, 숫자값을 real
(float4
) 타입으로 처리하려면 다음과 같이 작성한다:
REAL '1.23' -- 문자열 스타일
1.23::REAL -- PostgreSQL (전통적) 스타일
이는 다음 절에서 설명할 일반적인 캐스팅 표기법의 특수한 경우이다.
임의의 타입 상수는 다음 세 가지 방법 중 하나로 입력할 수 있다:
type '문자열'
'문자열'::type
CAST ( '문자열' AS type )
문자열 상수의 텍스트는 type
이라는 타입의 입력 변환 루틴으로 전달된다. 그 결과로 지정된 타입의 상수가 생성된다. 상수의 타입이 명확한 경우(예: 테이블 컬럼에 직접 할당되는 경우)에는 명시적인 타입 캐스트를 생략할 수 있으며, 이때는 자동으로 타입이 강제 변환된다.
문자열 상수는 일반 SQL 표기법이나 달러 쿼트(dollar-quoting) 방식으로 작성할 수 있다.
함수와 유사한 문법을 사용한 타입 변환도 가능하다:
typename ( '문자열' )
단, 모든 타입 이름이 이 방식을 사용할 수 있는 것은 아니다. 자세한 내용은 4.2.9절을 참고한다.
::
, CAST()
, 그리고 함수 호출 문법은 4.2.9절에서 설명하는 것처럼 임의의 표현식에 대한 실행 시간 타입 변환을 지정할 때도 사용할 수 있다. 문법적 모호성을 피하기 위해 type '문자열'
문법은 단순 리터럴 상수의 타입을 지정할 때만 사용할 수 있다. 또한 type '문자열'
문법은 배열 타입에는 사용할 수 없으므로, 배열 상수의 타입을 지정할 때는 ::
나 CAST()
를 사용해야 한다.
CAST()
문법은 SQL 표준을 준수한다. type '문자열'
문법은 표준을 일반화한 것이다. SQL 표준은 이 문법을 일부 데이터 타입에만 지정하고 있지만, PostgreSQL은 모든 타입에 대해 이를 허용한다. ::
를 사용하는 문법과 함수 호출 문법은 PostgreSQL의 고유 기능이다.
연산자 이름은 기본값으로 최대 NAMEDATALEN
-1(기본값 63) 길이까지 다음 문자들로 구성할 수 있다:
+ - * / < > = ~ ! @ # % ^ & | ` ?
다만 연산자 이름에는 몇 가지 제한 사항이 있다:
--
와 /*
는 주석의 시작으로 인식되기 때문에 연산자 이름에 포함할 수 없다.
두 글자 이상으로 구성된 연산자 이름은 다음 문자 중 하나를 포함하지 않는 한 +
나 -
로 끝날 수 없다:
~ ! @ # % ^ & | ` ?
예를 들어, @-
는 허용되는 연산자 이름이지만 *-
는 허용되지 않는다. 이러한 제한은 PostgreSQL이 토큰 사이에 공백 없이도 SQL 표준을 준수하는 쿼리를 구문 분석할 수 있게 한다.
SQL 표준을 따르지 않는 연산자 이름을 사용할 때는 모호성을 피하기 위해 일반적으로 연산자 사이에 공백을 넣어야 한다. 예를 들어, @
라는 이름의 접두 연산자를 정의했다면 X*@Y
와 같이 작성할 수 없다. PostgreSQL이 하나가 아닌 두 개의 연산자 이름으로 인식하도록 X* @Y
와 같이 작성해야 한다.
영숫자가 아닌 일부 문자들은 연산자와는 다른 특별한 의미를 가진다. 각 문자의 자세한 용법은 해당 문법 요소를 설명하는 부분에서 확인할 수 있다. 이 절에서는 이러한 특수 문자의 존재를 알리고 그 용도를 요약하여 설명한다.
달러 기호($
)와 숫자를 조합하면 함수 정의나 준비된 구문에서 위치 매개변수를 표현할 수 있다. 다른 문맥에서 달러 기호는 식별자나 달러 따옴표로 묶인 문자열 상수의 일부가 될 수 있다.
소괄호(()
)는 일반적인 의미대로 표현식을 그룹화하고 우선순위를 지정한다. 특정 SQL 명령의 고정 문법에서는 소괄호가 필수로 들어가야 한다.
대괄호([]
)는 배열의 요소를 선택할 때 사용한다. 배열에 대한 자세한 내용은 8.15절을 참조한다.
쉼표(,
)는 특정 문법 구조에서 목록의 요소를 구분하는 데 사용한다.
세미콜론(;
)은 SQL 명령을 종료한다. 문자열 상수나 따옴표로 묶인 식별자 내부를 제외하고는 명령 중간에 사용할 수 없다.
콜론(:
)은 배열에서 “슬라이스”를 선택할 때 사용한다. (8.15절 참조) 일부 SQL 방언(예: 임베디드 SQL)에서는 변수 이름 앞에 콜론을 붙인다.
별표(*
)는 테이블 행이나 복합 값의 모든 필드를 나타내는 문맥에서 사용한다. 또한 집계 함수의 인자로 사용될 때는 해당 집계가 명시적인 매개변수를 필요로 하지 않는다는 특별한 의미를 가진다.
마침표(.
)는 숫자 상수에서 사용되며, 스키마, 테이블, 컬럼 이름을 구분할 때도 사용한다.
표 4.2”)는 PostgreSQL의 연산자 우선순위와 결합 방향을 보여준다. 대부분의 연산자는 동일한 우선순위를 가지며 왼쪽에서 오른쪽으로 결합한다. 파서는 연산자의 우선순위와 결합 방향을 내부적으로 고정해 처리한다. 여러 연산자가 포함된 표현식을 우선순위 규칙과 다르게 해석하려면 괄호를 추가해야 한다.
표 4.2. 연산자 우선순위(높은 순에서 낮은 순)
연산자/요소 | 결합 방향 | 설명 |
---|---|---|
. | 왼쪽 | 테이블/컬럼명 구분자 |
:: | 왼쪽 | PostgreSQL 스타일 타입 변환 |
[ ] | 왼쪽 | 배열 요소 선택 |
+ - | 오른쪽 | 단항 플러스, 단항 마이너스 |
COLLATE | 왼쪽 | 문자 정렬 방식 선택 |
AT | 왼쪽 | AT TIME ZONE, AT LOCAL |
^ | 왼쪽 | 지수 계산 |
* / % | 왼쪽 | 곱셈, 나눗셈, 나머지 연산 |
+ - | 왼쪽 | 덧셈, 뺄셈 |
(기타 연산자) | 왼쪽 | 그 외 모든 내장 및 사용자 정의 연산자 |
BETWEEN IN LIKE ILIKE SIMILAR | 범위 포함, 집합 멤버십, 문자열 매칭 | |
< > = <= >= <> | 비교 연산자 | |
IS ISNULL NOTNULL | IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM 등 | |
NOT | 오른쪽 | 논리 부정 |
AND | 왼쪽 | 논리곱 |
OR | 왼쪽 | 논리합 |
이러한 연산자 우선순위 규칙은 위에서 언급한 내장 연산자와 동일한 이름을 가진 사용자 정의 연산자에도 적용된다. 예를 들어, 특정 데이터 타입에 대해 “+” 연산자를 새로 정의하더라도, 그 연산자가 수행하는 작업과 상관없이 내장 “+” 연산자와 동일한 우선순위를 가진다.
OPERATOR
구문에서 스키마가 명시된 연산자 이름을 사용할 때(예: 아래와 같은 경우)
SELECT 3 OPERATOR(pg_catalog.+) 4;
OPERATOR
구문은 표 4.2”)에서 “기타 연산자”에 해당하는 기본 우선순위를 가진다. 이는 OPERATOR()
내부에 어떤 특정 연산자가 있든 관계없이 동일하게 적용된다.
PostgreSQL 9.5 이전 버전에서는 현재와 다른 연산자 우선순위 규칙을 사용했다. 주요 차이점은 다음과 같다:
<=
, >=
, <>
연산자를 일반 연산자로 취급했다IS
테스트의 우선순위가 더 높았다NOT BETWEEN
과 관련 구문이 일관성 없이 동작했다. 일부 경우에는 BETWEEN
이 아닌 NOT
의 우선순위를 따랐다이러한 규칙은 SQL 표준을 더 잘 준수하고 논리적으로 동일한 구문의 불일치한 처리를 줄이기 위해 변경되었다. 대부분의 경우 이러한 변경으로 인한 동작 차이는 없다. 괄호를 추가하면 해결할 수 있는 “해당 연산자가 없음” 오류가 발생할 수 있다. 하지만 드물게 구문 오류가 보고되지 않으면서 쿼리의 동작이 변경될 수 있는 예외적인 경우도 존재한다.