쿼리 구문

쿼리 문은 테이블 또는 표현식을 한 개 이상 스캔하고 계산된 결과 행을 반환합니다. 이 주제는 Cloud Spanner SQL의 SQL 쿼리 구문을 설명합니다.

SQL 구문

query_statement:
    [ statement_hint_expr ][ table_hint_expr ][ join_hint_expr ]
query_expr statement_hint_expr: '@{' statement_hint_key = statement_hint_value [, ...] '}' statement_hint_key: { USE_ADDITIONAL_PARALLELISM| OPTIMIZER_VERSION } query_expr: [ WITH with_query_name AS ( query_expr ) [, ...] ] { select | ( query_expr ) | query_expr set_op query_expr } [ ORDER BY expression [{ ASC | DESC }] [, ...] ] [ LIMIT count [ OFFSET skip_rows ] ] select: SELECT [{ ALL | DISTINCT }] { [ expression. ]* | expression [ [ AS ] alias ] } [, ...] [ FROM from_item [ tablesample_type ] [, ...] ] [ WHERE bool_expression ] [ GROUP BY expression [, ...] ] [ HAVING bool_expression ] set_op: UNION { ALL | DISTINCT } | INTERSECT { ALL | DISTINCT } | EXCEPT { ALL | DISTINCT } from_item: { table_name [ table_hint_expr ] [ [ AS ] alias ] | join | ( query_expr ) [ table_hint_expr ] [ [ AS ] alias ] | field_path | { UNNEST( array_expression ) | UNNEST( array_path ) | array_path } [ table_hint_expr ] [ [ AS ] alias ] [ WITH OFFSET [ [ AS ] alias ] ] | with_query_name [ table_hint_expr ] [ [ AS ] alias ] } table_hint_expr: '@{' table_hint_key = table_hint_value '}' table_hint_key: { FORCE_INDEX | GROUPBY_SCAN_OPTIMIZATION } join: from_item [ join_type ] [ join_method ] JOIN [ join_hint_expr ] from_item [ { ON bool_expression | USING ( join_column [, ...] ) } ] join_type: { INNER | CROSS | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }

join_method:
{ HASH }
join_hint_expr: '@{' join_hint_key = join_hint_value [, ...] '}' join_hint_key: { FORCE_JOIN_ORDER | JOIN_METHOD } tablesample_type: TABLESAMPLE sample_method (sample_size percent_or_rows ) sample_method: { BERNOULLI | RESERVOIR } sample_size: numeric_value_expression percent_or_rows: { PERCENT | ROWS }

표기 규칙

  • 대괄호 '[ ]'는 절(선택사항)을 의미합니다.
  • 괄호 '( )'는 리터럴 괄호를 의미합니다.
  • 세로 막대 '|'는 논리 OR을 의미합니다.
  • 중괄호 '{ }'는 옵션 조합을 묶는 데 사용됩니다.
  • 꺾쇠 괄호 '[, ...]' 안에 있는 쉼표 다음에 오는 줄임표는 앞의 항목이 쉼표로 구분된 목록으로 반복될 수 있음을 의미합니다.

문 힌트

쿼리 문에는 다음과 같은 힌트가 지원됩니다.

힌트 키 가능한 값 설명
USE_ADDITIONAL_PARALLELISM TRUE
FALSE(기본값)
TRUE이면 실행 엔진은 가능한 한 더 많은 동시 로드를 사용합니다. 이로 인해 다른 작업에 사용할 수 있는 리소스가 줄어들 수 있으므로 동일한 인스턴스에서 지연 시간에 민감한 작업을 실행하는 경우에는 이 힌트를 사용하지 않는 것이 좋습니다.
OPTIMIZER_VERSION 1~N|latest 지정된 옵티마이저 버전을 사용하여 쿼리를 실행합니다. 가능한 값은 1~N(최신 옵티마이저 버전) 또는 latest입니다. 힌트가 설정되지 않은 경우 옵티마이저는 데이터베이스 옵션에 설정되거나 클라이언트 API를 통해 지정된 버전에 대해 실행됩니다. 둘 다 설정되지 않은 경우 옵티마이저는 기본적으로 최신 버전으로 설정됩니다.

버전 설정 우선 순위는 클라이언트 API에 의해 설정된 값이 데이터베이스 옵션의 값보다 우선하며 이 힌트에 의해 설정된 값이 다른 모든 값보다 우선합니다.

자세한 내용은 쿼리 옵티마이저를 참조하세요.

샘플 테이블

다음 테이블은 이 참조에서 다양한 쿼리 절의 동작을 설명하는 데 사용됩니다.

Roster 테이블

Roster 테이블에는 선수 이름 (LastName) 목록과 해당 학교에 할당된 고유 ID (SchoolID) 목록이 포함되어 있습니다. 아키텍처의 형태는 다음과 같습니다.

+-----------------------+
| LastName   | SchoolID |
+-----------------------+
| Adams      | 50       |
| Buchanan   | 52       |
| Coolidge   | 52       |
| Davis      | 51       |
| Eisenhower | 77       |
+-----------------------+

WITH 절을 사용하여 이 참조의 예에 대한 임시 테이블 이름을 에뮬레이션 할 수 있습니다.

WITH Roster AS
 (SELECT 'Adams' as LastName, 50 as SchoolID UNION ALL
  SELECT 'Buchanan', 52 UNION ALL
  SELECT 'Coolidge', 52 UNION ALL
  SELECT 'Davis', 51 UNION ALL
  SELECT 'Eisenhower', 77)
SELECT * FROM Roster

PlayerStats 테이블

PlayerStats 테이블에는 선수 이름(LastName) 목록과 주어진 경기의 상대에게 할당된 고유 ID(OpponentID)와 해당 경기에서 선수가 기록한 점수(PointsScored)가 포함되어 있습니다.

+----------------------------------------+
| LastName   | OpponentID | PointsScored |
+----------------------------------------+
| Adams      | 51         | 3            |
| Buchanan   | 77         | 0            |
| Coolidge   | 77         | 1            |
| Davis      | 52         | 4            |
| Eisenhower | 50         | 13           |
+----------------------------------------+

WITH 절을 사용하여 이 참조의 예에 대한 임시 테이블 이름을 에뮬레이션 할 수 있습니다.

WITH PlayerStats AS
 (SELECT 'Adams' as LastName, 51 as OpponentID, 3 as PointsScored UNION ALL
  SELECT 'Buchanan', 77, 0 UNION ALL
  SELECT 'Coolidge', 77, 1 UNION ALL
  SELECT 'Adams', 52, 4 UNION ALL
  SELECT 'Buchanan', 50, 13)
SELECT * FROM PlayerStats

TeamMascot 테이블

TeamMascot 테이블에는 고유한 학교 ID (SchoolID) 목록과 해당 학교의 마스코트(Mascot)가 포함되어 있습니다.

+---------------------+
| SchoolID | Mascot   |
+---------------------+
| 50       | Jaguars  |
| 51       | Knights  |
| 52       | Lakers   |
| 53       | Mustangs |
+---------------------+

WITH 절을 사용하여 이 참조의 예에 대한 임시 테이블 이름을 에뮬레이션 할 수 있습니다.

WITH TeamMascot AS
 (SELECT 50 as SchoolID, 'Jaguars' as Mascot UNION ALL
  SELECT 51, 'Knights' UNION ALL
  SELECT 52, 'Lakers' UNION ALL
  SELECT 53, 'Mustangs')
SELECT * FROM TeamMascot

SELECT 목록

구문:

SELECT  [{ ALL | DISTINCT }]
    { [ expression. ]* | expression [ [ AS ] alias ] } [, ...]

SELECT 목록은 쿼리가 반환할 열을 정의합니다. SELECT 목록의 표현식은 해당하는 FROM 절에서 from_item의 열을 참조할 수 있습니다.

SELECT 목록의 각 항목은 다음 중 하나입니다.

  • *
  • expression
  • expression.*

SELECT *

SELECT *select star라고 읽으며 전체 쿼리를 실행한 후에 표시되는 열마다 출력 열을 한 개씩 생성합니다.

SELECT * FROM (SELECT "apple" AS fruit, "carrot" AS vegetable);

+-------+-----------+
| fruit | vegetable |
+-------+-----------+
| apple | carrot    |
+-------+-----------+

SELECT expression

SELECT 목록의 항목은 표현식일 수 있습니다. 표현식은 단일 값으로 평가되며 명시적 alias(선택사항)가 있는 출력 열 한 개를 생성합니다.

표현식에 명시적 별칭이 없는 경우 가능하면 암시적 별칭 규칙에 따라 암시적 별칭을 수신합니다. 그 밖의 경우 열은 익명이며, 이름을 쿼리의 다른 곳에서 참조할 수 없습니다.

SELECT expression.*

SELECT 목록의 항목은 expression.* 형식을 취할 수도 있습니다. 그러면 expression의 열 또는 최상위 필드마다 출력 열이 한 개씩 생성됩니다. 이 표현식은 테이블 별칭이거나 STRUCT와 같은 필드가 있는 데이터 유형의 단일 값으로 평가되어야 합니다.

다음 쿼리는 테이블 groceries(별칭: g)의 열마다 출력 열을 한 개씩 생성합니다.

WITH groceries AS
  (SELECT "milk" AS dairy,
   "eggs" AS protein,
   "bread" AS grain)
SELECT g.*
FROM groceries AS g;

+-------+---------+-------+
| dairy | protein | grain |
+-------+---------+-------+
| milk  | eggs    | bread |
+-------+---------+-------+

기타 예:

WITH locations AS
  (SELECT STRUCT("Seattle" AS city, "Washington" AS state) AS location
  UNION ALL
  SELECT STRUCT("Phoenix" AS city, "Arizona" AS state) AS location)
SELECT l.location.*
FROM locations l;

+---------+------------+
| city    | state      |
+---------+------------+
| Seattle | Washington |
| Phoenix | Arizona    |
+---------+------------+
WITH locations AS
  (SELECT ARRAY<STRUCT<city STRING, state STRING>>[("Seattle", "Washington"),
    ("Phoenix", "Arizona")] AS location)
SELECT l.LOCATION[offset(0)].*
FROM locations l;

+---------+------------+
| city    | state      |
+---------+------------+
| Seattle | Washington |
+---------+------------+

SELECT 수정자

다음과 같이 SELECT 쿼리에서 반환된 결과를 수정할 수 있습니다.

SELECT DISTINCT

SELECT DISTINCT 문은 중복 행을 삭제하고 나머지 행만 반환합니다. SELECT DISTINCT는 다음 유형의 열을 반환할 수 없습니다.

  • STRUCT
  • ARRAY

SELECT ALL

SELECT ALL 문은 중복 행을 포함한 모든 행을 반환합니다. SELECT ALLSELECT의 기본 동작입니다.

SELECT와 함께 STRUCT 사용

  • 반환 유형의 루트에서 STRUCT를 반환하는 쿼리는 지원되지 않습니다. 예를 들어 다음 쿼리는 지원되지 않습니다.

    SELECT STRUCT(1, 2) FROM Users;
    
  • 반환 유형의 루트에서 구조체 배열 반환이 지원됩니다. 예를 들어, 다음 쿼리가 지원됩니다.

    SELECT ARRAY(SELECT STRUCT(1, 2)) FROM Users;
    
  • 그러나 쿼리 결과에 NULL 구조체를 반환할 수 있는 쿼리 셰이프는 지원되지 않으므로, 다음 쿼리는 지원되지 않습니다.

    SELECT ARRAY(SELECT IF(TRUE, STRUCT(1, 2), NULL)) FROM Users;
    

ARRAY 내에서 STRUCTs를 쿼리하는 방법에 대한 자세한 예시는 ARRAY의 STRUCT 요소 쿼리를 참조하세요.

서브 쿼리에서의 STRUCTs 사용에 대한 참고사항도 참조하세요.

별칭

SELECT 목록 별칭의 구문과 표시 여부는 별칭 사용을 참조하세요.

FROM 절

FROM 절은 행을 검색할 테이블을 표시하고 나머지 쿼리에서 처리할 단일 행 스트림을 생성하기 위해 해당 행을 조인하는 방법을 지정합니다.

구문

from_item: {
    table_name [ table_hint_expr ] [ [ AS ] alias ] |
    join |
    ( query_expr ) [ table_hint_expr ] [ [ AS ] alias ] |
    field_path |
    { UNNEST( array_expression ) | UNNEST( array_path ) | array_path }
        [ table_hint_expr ] [ [ AS ] alias ] [ WITH OFFSET [ [ AS ] alias ] ] |
    with_query_name [ table_hint_expr ] [ [ AS ] alias ]
}
table_hint_expr: '@{' table_hint_key = table_hint_value '}' table_hint_key: { FORCE_INDEX | GROUPBY_SCAN_OPTIMIZATION }

table_name

기존 테이블의 이름입니다.

SELECT * FROM Roster;
테이블 힌트

테이블에 대해 다음과 같은 힌트가 지원됩니다.

힌트 키 가능한 값 설명
FORCE_INDEX 문자열. 데이터베이스의 기존 색인 이름 또는 색인이 아닌 기본 테이블을 사용하는 _BASE_TABLE.
  • 색인 이름으로 설정되면 기본 테이블 대신 해당 색인을 사용합니다. 색인이 필요한 모든 열을 제공할 수 없는 경우, 기본 테이블을 사용하여 다시 조인합니다.
  • 문자열 _BASE_TABLE로 설정된 경우 색인 대신 색인 전략의 기본 테이블을 사용합니다. 문 힌트 표현식에서 FORCE_INDEX가 사용되는 경우 이 값만 유효한 값입니다.

참고: FORCE_INDEX는 실제로는 힌트가 아니라 지시문이므로 색인이 없으면 오류가 발생합니다.

GROUPBY_SCAN_OPTIMIZATION TRUE
FALSE

그룹화 기준 스캔 최적화를 사용하면 GROUP BY 또는 SELECT DISTINCT를 사용하는 쿼리를 더 빨리 실행할 수 있습니다. 그룹화 키가 기본 테이블 또는 색인 키의 프리픽스를 형성할 수 있으며 쿼리가 각 그룹의 첫 번째 행만 필요로 하는 경우에 이러한 최적화를 적용할 수 있습니다.

옵티마이저가 쿼리를 더 효율적으로 수행할 것으로 예상하는 경우 최적화가 적용됩니다. 힌트는 그러한 결정보다 우선합니다. 힌트를 FALSE로 설정하면 최적화가 고려되지 않습니다. 힌트가 TRUE로 설정된 경우에는 적절한 경우에 최적화가 적용됩니다.

다음 예시에서는 테이블 이름에 @{FORCE_INDEX=index_name} 형식의 색인 지시문을 추가하여 테이블 내용을 읽을 때 보조 색인을 사용하는 방법을 보여줍니다.

SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo
FROM Singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName = "Catalina" AND s.LastName > "M";

각 개별 테이블 참조에 단일 색인만 지원되지만 쿼리에 색인을 여러 개 포함할 수 있습니다. 예:

SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo, c.ConcertDate
FROM Singers@{FORCE_INDEX=SingersByFirstLastName} AS s JOIN
     Concerts@{FORCE_INDEX=ConcertsBySingerId} AS c ON s.SingerId = c.SingerId
WHERE s.FirstName = "Catalina" AND s.LastName > "M";

보조 색인에서 색인 지시문을 자세히 알아보세요.

join

아래 JOIN 유형을 참조하세요.

select

( select ) [ [ AS ] alias ]테이블 서브 쿼리입니다.

field_path

FROM 절에서 field_path는 데이터 유형 내에서 필드로 해석되는 경로입니다. field_path는 중첩된 데이터 구조에서 임의의 깊이까지 들어갈 수 있습니다.

유효한 field_path 값의 몇 가지 예시는 다음과 같습니다.

SELECT * FROM T1 t1, t1.array_column;

SELECT * FROM T1 t1, t1.struct_column.array_field;

SELECT (SELECT ARRAY_AGG(c) FROM t1.array_column c) FROM T1 t1;

SELECT a.struct_field1 FROM T1 t1, t1.array_of_structs a;

SELECT (SELECT STRING_AGG(a.struct_field1) FROM t1.array_of_structs a) FROM T1 t1;

FROM 절의 필드 경로는 배열 필드에서 끝나야 합니다. 또한 필드 경로는 경로 끝 앞에 배열을 포함할 수 없습니다. 예를 들어 array_column.some_array.some_array_field 경로는 경로 끝 앞에 배열을 포함하고 있으므로 유효하지 않습니다.

참고: 경로에 이름이 한 개 뿐이면 경로는 테이블로 해석됩니다. 이 문제를 해결하려면 UNNEST를 사용하여 경로를 래핑하거나 정규화된 경로를 사용하세요.

참고: 경로에 이름이 두 개 이상 있고 이름이 필드 이름과 일치하면 필드 이름으로 해석됩니다. 경로를 테이블 이름으로 강제 해석하려면 `를 사용하여 경로를 래핑하세요.

UNNEST

UNNEST 연산자는 ARRAY를 취하고 ARRAY의 각 요소에 대한 행이 한 개씩 포함된 테이블을 반환합니다. FROM 절 외부의 UNNESTIN 연산자를 사용할 수도 있습니다.

대부분의 요소 유형의 입력 ARRAY의 경우 일반적으로 UNNEST 출력에는 열이 한 개 있습니다. 이 단일 열에는 alias(선택사항)가 있어 쿼리의 다른 위치에서 열을 참조할 때 사용될 수 있습니다. 이러한 요소 유형을 사용하는 ARRAYS는 열을 여러 개 반환합니다.

  • STRUCT

UNNEST는 입력 ARRAY의 요소 순서를 무시합니다. WITH OFFSET 절(선택사항)을 사용하면 배열 요소 색인을 포함한 두 번째 열을 반환할 수 있습니다(아래 참조).

STRUCT의 입력 ARRAY의 경우 UNNESTSTRUCT의 각 필드에 대해 별도의 열을 만들고 각 STRUCT마다 행 한 개를 반환합니다. 각 열의 별칭은 해당 STRUCT 필드의 이름입니다.

예시

SELECT *
FROM UNNEST(ARRAY<STRUCT<x INT64, y STRING>>[(1, 'foo'), (3, 'bar')]);

+---+-----+
| x | y   |
+---+-----+
| 3 | bar |
| 1 | foo |
+---+-----+

ARRAY 중첩 해제는 명시적이거나 암시적일 수 있습니다. 명시적 중첩 해제에서 array_expression은 ARRAY 값을 반환해야 하지만 ARRAY로 해석될 필요는 없으며 UNNEST 키워드가 필요합니다.

예:

SELECT * FROM UNNEST ([1, 2, 3]);

암시적 중첩 해제에서 array_path는 ARRAY로 해석되어야 하며 UNNEST 키워드는 선택사항입니다.

예:

SELECT x
FROM mytable AS t,
  t.struct_typed_column.array_typed_field1 AS x;

이 시나리오에서 array_path는 데이터 구조의 임의의 깊이까지 들어갈 수 있지만 마지막 필드는 ARRAY 유형이어야 합니다. ARRAY에서 명명된 필드를 추출할 수 없으므로 표현식의 이전 필드는 ARRAY 유형일 수 없습니다.

UNNEST는 NULL을 다음과 같이 처리합니다.

  • NULL과 빈 ARRAY는 행 0개를 생성합니다.
  • NULL을 포함하는 ARRAY는 NULL 값을 포함하는 행을 생성합니다.

선택사항인 WITH OFFSET 절은 UNNEST 연산으로 생성된 각 행의 'offset' 값(즉, 카운트가 0에서 시작)을 포함하는 별도의 열을 반환합니다. 이 열에는 alias(선택사항)이 있고, 기본 별칭은 offset입니다.

예를 들면 다음과 같습니다.

SELECT * FROM UNNEST ( ) WITH OFFSET AS num;

생성, 평면화, 필터링을 포함하여 UNNEST를 사용하는 보다 다양한 방법은 Arrays topic를 참조하세요.

with_query_name

WITH 절의 쿼리 이름(WITH 절 참조)은 FROM 절의 어디에서나 참조할 수 있는 임시 테이블 이름과 같은 역할을 수행합니다. 아래 예시에서 subQ1subQ2with_query_names입니다.

예를 들면 다음과 같습니다.

WITH
  subQ1 AS (SELECT * FROM Roster WHERE SchoolID = 52),
  subQ2 AS (SELECT SchoolID FROM subQ1)
SELECT DISTINCT * FROM subQ2;

사용자가 테이블 이름을 한정하지 않는 한(예: db.Roster) WITH 절은 쿼리 기간 동안 같은 이름의 영구 테이블을 숨깁니다.

TABLESAMPLE 연산자

TABLESAMPLE 연산자를 사용하여 데이터 집합의 무작위 샘플을 선택할 수 있습니다. 이 연산자는 많은 양의 데이터가 있고 정확한 답변이 필요하지 않은 테이블을 사용하여 작업하는 경우에 유용합니다.

구문:

tablesample_type:
    TABLESAMPLE sample_method (sample_size percent_or_rows)

sample_method:
    { BERNOULLI | RESERVOIR }

sample_size:
    numeric_value_expression

percent_or_rows:
    { PERCENT | ROWS }

TABLESAMPLE 연산자 사용 시 사용할 샘플링 알고리즘을 지정해야 합니다.

  • BERNOULLI - 각 행이 percent 절에 주어진 확률로 독립적으로 선택됩니다. 결과적으로 약 N * percent/100개의 행이 생깁니다.

  • RESERVOIR - 실제 샘플 크기 K(행 수로 표현됨)를 매개변수로 사용합니다. 입력이 K보다 작으면 전체 입력 관계를 출력합니다. 입력이 K보다 크면 저장소 샘플링은 크기 K와 정확한 샘플을 출력합니다. 여기서 크기 K의 모든 샘플은 거의 동일합니다.

TABLESAMPLE 연산자를 사용하려면 ROWS 또는 PERCENT를 선택해야 합니다. PERCENT를 선택할 경우 값은 0에서 100 사이여야 합니다. ROWS를 선택할 경우 값은 0보다 크거나 같아야 합니다.

다음 예시에서는 TABLESAMPLE 연산자의 사용 방법을 보여줍니다.

RESERVOIR 샘플링 방법을 사용하여 테이블에서 선택:

SELECT MessageId
FROM Messages TABLESAMPLE RESERVOIR (100 ROWS);

BERNOULLI 샘플링 방법을 사용하여 테이블에서 선택:

SELECT MessageId
FROM Messages TABLESAMPLE BERNOULLI (0.1 PERCENT);

서브 쿼리와 함께 TABLESAMPLE 사용:

SELECT Subject FROM
(SELECT MessageId, Subject FROM Messages WHERE ServerId="test")
TABLESAMPLE BERNOULLI(50 PERCENT)
WHERE MessageId > 3;

다른 테이블의 조인과 함께 TABLESAMPLE 연산 사용:

SELECT S.Subject
FROM
(SELECT MessageId, ThreadId FROM Messages WHERE ServerId="test") AS R
TABLESAMPLE RESERVOIR(5 ROWS),
Threads AS S
WHERE S.ServerId="test" AND R.ThreadId = S.ThreadId;

별칭

FROM 절 별칭의 구문과 표시 여부는 별칭 사용을 참조하세요.

JOIN 유형

구문

join:
    from_item [ join_type ] [ join_method ] JOIN  [ join_hint_expr ] from_item
    [ ON bool_expression | USING ( join_column [, ...] ) ]

join_type:
    { INNER | CROSS | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }

join_method:
{ HASH }
join_hint_expr: '@{' join_hint_key = join_hint_value [, ...] '}' join_hint_key: { FORCE_JOIN_ORDER | JOIN_METHOD }

JOIN 절은 from_item 두 개를 병합하여 SELECT 절이 이들을 소스 한 개로 쿼리할 수 있도록 합니다. join_typeON 또는 USING 절('조인 조건')은 단일 소스를 형성하도록 from_item 두 개에서 행을 결합 및 삭제하는 방법을 지정합니다.

모든 JOIN 절에 join_type이 있어야 합니다.

다음 조건 중 하나가 true인 경우를 제외하고 JOIN 절에 조인 조건이 필요합니다.

  • join_typeCROSS입니다.
  • from_item 중 하나 또는 둘 모두가 테이블이 아닙니다(예: array_path 또는 field_path).

Join 힌트

JOIN에 다음 힌트가 지원됩니다.

힌트 키 가능한 값 설명
FORCE_JOIN_ORDER TRUE
FALSE(기본값)
True로 설정하면 쿼리에 지정된 조인 순서가 사용됩니다.
JOIN_METHOD HASH_JOIN
APPLY_JOIN
논리적 조인 구현 시 기본 조인 메서드에 사용할 특정 대안을 선택합니다. 조인 메서드에서 자세히 알아보세요.
HASH 조인을 사용하려면 HASH JOIN 또는 JOIN@{JOIN_METHOD=HASH_JOIN} 중 하나만 사용합니다.
HASH_JOIN_BUILD_SIDE BUILD_LEFT
BUILD_RIGHT
빌드 측으로 해시 조인의 어느 쪽이 사용되는지를 지정합니다. JOIN_METHOD=HASH_JOIN으로만 사용할 수 있습니다.
BATCH_MODE TRUE (default)
FALSE
한 번에 하나의 행을 적용하기 위해 일괄 적용 조인을 사용 중지하는 데 사용됩니다. JOIN_METHOD=APPLY_JOIN으로만 사용할 수 있습니다.

조인 메서드

조인 메서드는 다양한 논리적 조인 유형이 특정하게 구현된 것입니다. 일부 조인 메소드는 특정 조인 유형에만 사용할 수 있습니다. 퀴리의 구체적 내용과 쿼리 대상 데이터에 따라 사용할 조인 메소드를 선택합니다. 특정 조인 메소드가 쿼리 수행에 유용한지 확인하는 가장 좋은 방법은 메소드를 시도하고 결과 쿼리 실행 계획을 보는 것입니다. 자세한 내용은 쿼리 실행 연산자의 적용 및 해시 조인 연산자 관련 섹션을 참조하세요.

조인 메소드 설명 피연산자
HASH_JOIN 해시 조인 연산자는 한쪽(빌드 측)에서 해시 테이블을 작성하고 다른 쪽(프로브 측)의 모든 요소에 대해 해시 테이블에서 프로브를 작성합니다. 여러 가지 변형이 다양한 조인 유형에 사용됩니다. 쿼리의 쿼리 실행 계획에서 어떤 변형이 사용되고 있는지 확인합니다. 해시 조인 연산자에 대해 자세히 알아보세요.
APPLY_JOIN 적용 조인 연산자는 각 항목을 한쪽(입력 측)에서 가져오고 입력 측의 항목 값을 사용하여 다른 쪽(맵 측)에서 서브 쿼리를 평가합니다. 여러 가지 변형이 다양한 조인 유형에 사용됩니다. 교차 적용은 내부 조인에 사용되고 외부 적용은 왼쪽 조인에 사용됩니다. 교차 적용외부 적용 연산자에 대해 자세히 알아보세요.

[INNER] JOIN

INNER JOIN(또는 간단히 JOIN)은 두 from_item의 카티전 프로덕트를 사실상 계산하며 조인 조건을 충족하지 않는 모든 행을 삭제합니다. 여기서 '사실상'이란 실제로 카티전 프로덕트를 계산하지 않고 INNER JOIN을 구현할 수 있음을 의미합니다.

FROM A INNER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------+
| w | x |  *  | y | z |  =  | w | x | y | z |
+-------+     +-------+     +---------------+
| 1 | a |     | 2 | d |     | 2 | b | 2 | d |
| 2 | b |     | 3 | e |     | 3 | c | 3 | e |
| 3 | c |     | 4 | f |     +---------------+
+-------+     +-------+
FROM A INNER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +-----------+
| x | y |  *  | x | z |  =  | x | y | z |
+-------+     +-------+     +-----------+
| 1 | a |     | 2 | d |     | 2 | b | d |
| 2 | b |     | 3 | e |     | 3 | c | e |
| 3 | c |     | 4 | f |     +-----------+
+-------+     +-------+

예시

이 쿼리는 RosterTeamMascot 테이블에서 INNER JOIN을 수행합니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
+---------------------------+

CROSS JOIN

CROSS JOIN은 두 from_item의 카티전 프로덕트를 반환합니다. 즉, 첫 번째 from_item의 각 행과 두 번째 from_item의 각 행을 결합합니다.

2개의 from_item 행이 독립적이면 결과에 M * N개 행이 포함되며, M개 행은 1개의 from_item에 있고 N개 행은 다른 항목에 있습니다. from_item에 행이 없는 경우에도 이 규칙이 적용됩니다.

FROM A CROSS JOIN B

Table A       Table B       Result
+-------+     +-------+     +---------------+
| w | x |  *  | y | z |  =  | w | x | y | z |
+-------+     +-------+     +---------------+
| 1 | a |     | 2 | c |     | 1 | a | 2 | c |
| 2 | b |     | 3 | d |     | 1 | a | 3 | d |
+-------+     +-------+     | 2 | b | 2 | c |
                            | 2 | b | 3 | d |
                            +---------------+

상관된 CROSS JOIN을 사용하여 ARRAY 열을 평면화할 수 있습니다. 이 경우 두 번째 from_item의 행은 첫 번째 from_item의 각 행과 다릅니다.

FROM A CROSS JOIN A.y

Table A                    Result
+-------------------+      +-----------+
| w | x | y         |  ->  | w | x | y |
+-------------------+      +-----------+
| 1 | a | [P, Q]    |      | 1 | a | P |
| 2 | b | [R, S, T] |      | 1 | a | Q |
+-------------------+      | 2 | b | R |
                           | 2 | b | S |
                           | 2 | b | T |
                           +-----------+

CROSS JOIN은 다음과 같이 명시적으로 작성할 수 있습니다.

FROM a CROSS JOIN b

또는 다음과 같이 암시적으로 쉼표 교차 조인으로 사용합니다.

FROM a, b

괄호 안에 쉼표 교차 조인을 작성할 수 없습니다.

FROM a CROSS JOIN (b, c)  // INVALID

JOIN 시퀀스에서 쉼표 교차 조인의 작동 방식에 대한 자세한 내용은 JOIN 시퀀스를 참조하세요.

예시

이 쿼리는 RosterTeamMascot 테이블에서 명시적인 CROSS JOIN을 수행합니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster CROSS JOIN TeamMascot;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Adams      | Knights      |
| Adams      | Lakers       |
| Adams      | Mustangs     |
| Buchanan   | Jaguars      |
| Buchanan   | Knights      |
| Buchanan   | Lakers       |
| Buchanan   | Mustangs     |
| ...                       |
+---------------------------+

이 쿼리는 위의 명시적 CROSS JOIN과 동일한 결과를 생성하는 쉼표 교차 조인을 수행합니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster, TeamMascot;

FULL [OUTER] JOIN

FULL OUTER JOIN(또는 간단히 FULL JOIN)은 두 from_item에서 조인 조건을 충족하는 모든 행의 모든 필드를 반환합니다.

FULL은 조인 조건이 충족되지 않더라도 두 from_item모든 행이 반환됨을 나타냅니다.

OUTER는 한 from_item에서 지정된 행이 다른 from_item의 어떠한 행에도 조인되지 않으면 행은 다른 from_item의 모든 열에서 NULL로 반환됨을 나타냅니다.

FROM A FULL OUTER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------------------+
| w | x |  *  | y | z |  =  | w    | x    | y    | z    |
+-------+     +-------+     +---------------------------+
| 1 | a |     | 2 | d |     | 1    | a    | NULL | NULL |
| 2 | b |     | 3 | e |     | 2    | b    | 2    | d    |
| 3 | c |     | 4 | f |     | 3    | c    | 3    | e    |
+-------+     +-------+     | NULL | NULL | 4    | f    |
                            +---------------------------+
FROM A FULL OUTER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +--------------------+
| x | y |  *  | x | z |  =  | x    | y    | z    |
+-------+     +-------+     +--------------------+
| 1 | a |     | 2 | d |     | 1    | a    | NULL |
| 2 | b |     | 3 | e |     | 2    | b    | d    |
| 3 | c |     | 4 | f |     | 3    | c    | e    |
+-------+     +-------+     | 4    | NULL | f    |
                            +--------------------+

예시

이 쿼리는 RosterTeamMascot 테이블에서 FULL JOIN을 수행합니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster FULL JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
| Eisenhower | NULL         |
| NULL       | Mustangs     |
+---------------------------+

LEFT [OUTER] JOIN

오른쪽 from_item의 행이 조인 조건을 충족하지 않더라도 두 from_item에 대한 한 LEFT OUTER JOIN(또는 간단히 LEFT JOIN)의 결과는 항상 JOIN 절에 있는 왼쪽 from_item의 모든 행을 유지합니다.

LEFT왼쪽 from_item의 모든 행이 반환됨을 나타냅니다. 왼쪽 from_item에서 지정된 행이 오른쪽 from_item의 어떠한 행에도 조인되지 않으면 행은 오른쪽 from_item의 모든 열에서 NULL로 반환됩니다. 왼쪽 from_item의 어떠한 행에도 조인되지 않는 오른쪽 from_item의 행은 삭제됩니다.

FROM A LEFT OUTER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------------------+
| w | x |  *  | y | z |  =  | w    | x    | y    | z    |
+-------+     +-------+     +---------------------------+
| 1 | a |     | 2 | d |     | 1    | a    | NULL | NULL |
| 2 | b |     | 3 | e |     | 2    | b    | 2    | d    |
| 3 | c |     | 4 | f |     | 3    | c    | 3    | e    |
+-------+     +-------+     +---------------------------+
FROM A LEFT OUTER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +--------------------+
| x | y |  *  | x | z |  =  | x    | y    | z    |
+-------+     +-------+     +--------------------+
| 1 | a |     | 2 | d |     | 1    | a    | NULL |
| 2 | b |     | 3 | e |     | 2    | b    | d    |
| 3 | c |     | 4 | f |     | 3    | c    | e    |
+-------+     +-------+     +--------------------+

예시

이 쿼리는 RosterTeamMascot 테이블에서 LEFT JOIN을 수행합니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster LEFT JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
| Eisenhower | NULL         |
+---------------------------+

RIGHT [OUTER] JOIN

RIGHT OUTER JOIN(또는 간단히 RIGHT JOIN) 결과는 LEFT OUTER JOIN 결과와 유사하며 대칭적입니다.

FROM A RIGHT OUTER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------------------+
| w | x |  *  | y | z |  =  | w    | x    | y    | z    |
+-------+     +-------+     +---------------------------+
| 1 | a |     | 2 | d |     | 2    | b    | 2    | d    |
| 2 | b |     | 3 | e |     | 3    | c    | 3    | e    |
| 3 | c |     | 4 | f |     | NULL | NULL | 4    | f    |
+-------+     +-------+     +---------------------------+
FROM A RIGHT OUTER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +--------------------+
| x | y |  *  | x | z |  =  | x    | y    | z    |
+-------+     +-------+     +--------------------+
| 1 | a |     | 2 | d |     | 2    | b    | d    |
| 2 | b |     | 3 | e |     | 3    | c    | e    |
| 3 | c |     | 4 | f |     | 4    | NULL | f    |
+-------+     +-------+     +--------------------+

예시

이 쿼리는 RosterTeamMascot 테이블에서 RIGHT JOIN을 수행합니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster RIGHT JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
| NULL       | Mustangs     |
+---------------------------+

ON 절

ON 절에는 bool_expression이 포함됩니다. bool_expression이 TRUE를 반환하면 결합된 행(두 행을 조인한 결과)은 조인 조건을 충족합니다.

FROM A JOIN B ON A.x = B.x

Table A   Table B   Result (A.x, B.x)
+---+     +---+     +-------+
| x |  *  | x |  =  | x | x |
+---+     +---+     +-------+
| 1 |     | 2 |     | 2 | 2 |
| 2 |     | 3 |     | 3 | 3 |
| 3 |     | 4 |     +-------+
+---+     +---+

예시

이 쿼리는 RosterTeamMascot 테이블에서 INNER JOIN을 수행합니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
+---------------------------+

USING 절

USING 절에는 두 입력 테이블 모두에서 발생하는 열이 한 개 이상인 column_list가 필요합니다. 이 절은 해당 열에서 동등 비교를 수행하고 동등 비교가 TRUE를 반환하면 행은 조인 조건을 충족합니다.

FROM A JOIN B USING (x)

Table A   Table B   Result
+---+     +---+     +---+
| x |  *  | x |  =  | x |
+---+     +---+     +---+
| 1 |     | 2 |     | 2 |
| 2 |     | 3 |     | 3 |
| 3 |     | 4 |     +---+
+---+     +---+

예시

이 쿼리는 RosterTeamMascot 테이블에서 INNER JOIN을 수행합니다.

이 문은 RosterTeamMascot의 행을 반환합니다. 여기서 Roster.SchooldIDTeamMascot.SchooldID과 동일합니다. 결과에는 SchooldID 열 한 개가 포함됩니다.

SELECT * FROM Roster INNER JOIN TeamMascot USING (SchoolID);

+----------------------------------------+
| SchoolID   | LastName   | Mascot       |
+----------------------------------------+
| 50         | Adams      | Jaguars      |
| 52         | Buchanan   | Lakers       |
| 52         | Coolidge   | Lakers       |
| 51         | Davis      | Knights      |
+----------------------------------------+

ON 및 USING 유사성

ONUSING 키워드는 동일하지는 않지만 비슷합니다. ON는 여러 열을 반환하고 USING는 한 개의 열을 반환합니다.

FROM A JOIN B ON A.x = B.x
FROM A JOIN B USING (x)

Table A   Table B   Result ON     Result USING
+---+     +---+     +-------+     +---+
| x |  *  | x |  =  | x | x |     | x |
+---+     +---+     +-------+     +---+
| 1 |     | 2 |     | 2 | 2 |     | 2 |
| 2 |     | 3 |     | 3 | 3 |     | 3 |
| 3 |     | 4 |     +-------+     +---+
+---+     +---+

ONUSING는 동일하지 않지만 반환하려는 열을 지정하면 동일한 결과를 반환할 수 있습니다.

SELECT x FROM A JOIN B USING (x);
SELECT A.x FROM A JOIN B ON A.x = B.x;

Table A   Table B   Result
+---+     +---+     +---+
| x |  *  | x |  =  | x |
+---+     +---+     +---+
| 1 |     | 2 |     | 2 |
| 2 |     | 3 |     | 3 |
| 3 |     | 4 |     +---+
+---+     +---+

JOIN 시퀀스

FROM 절은 시퀀스에 여러 JOIN 절을 포함 할 수 있습니다. JOIN은 왼쪽에서 오른쪽으로 바인딩됩니다. 예를 들면 다음과 같습니다.

FROM A JOIN B USING (x) JOIN C USING (x)

-- A JOIN B USING (x)        = result_1
-- result_1 JOIN C USING (x) = result_2
-- result_2                  = return value

JOIN 그룹에 괄호를 삽입할 수도 있습니다.

FROM ( (A JOIN B USING (x)) JOIN C USING (x) )

-- A JOIN B USING (x)        = result_1
-- result_1 JOIN C USING (x) = result_2
-- result_2                  = return value

괄호를 사용하면 JOIN을 그룹화하여 다른 순서로 바인딩할 수 있습니다.

FROM ( A JOIN (B JOIN C USING (x)) USING (x) )

-- B JOIN C USING (x)       = result_1
-- A JOIN result_1          = result_2
-- result_2                 = return value

JOIN 시퀀스를 포함한 쿼리에 쉼표 교차 조인이 있는 경우 다른 JOIN 유형과 마찬가지로 왼쪽에서 오른쪽으로 그룹화됩니다.

FROM A JOIN B USING (x) JOIN C USING (x), D

-- A JOIN B USING (x)        = result_1
-- result_1 JOIN C USING (x) = result_2
-- result_2 CROSS JOIN D     = return value

쉼표 조인 다음에는 RIGHT JOIN 또는 FULL JOIN이 올 수 없습니다.

FROM A, B RIGHT JOIN C ON TRUE // INVALID
FROM A, B FULL JOIN C ON TRUE  // INVALID
FROM A, B JOIN C ON TRUE       // VALID

WHERE 절

구문

WHERE bool_expression

WHERE 절은 bool_expression에 대해 각 행을 평가하여 행을 필터링하고 TRUE를 반환하지 않는 모든 행(즉, FALSE 또는 NULL을 반환하는 행)을 삭제합니다.

예:

SELECT * FROM Roster
WHERE SchoolID = 52;

bool_expression에는 하위 조건 여러 개가 포함될 수 있습니다.

예:

SELECT * FROM Roster
WHERE STARTS_WITH(LastName, "Mc") OR STARTS_WITH(LastName, "Mac");

WHERE 절에서 SELECT 목록의 열 별칭을 참조할 수 없습니다.

INNER JOIN 표현식은 WHERE 절에서 동일한 표현식을 가집니다. 예를 들어 INNER JOINON을 사용하는 쿼리에는 CROSS JOINWHERE를 사용하는 동등한 표현식이 있습니다.

예:

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster INNER JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

위 쿼리는 다음과 같습니다.

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster CROSS JOIN TeamMascot
WHERE Roster.SchoolID = TeamMascot.SchoolID;

GROUP BY 절

구문

GROUP BY expression [, ...]

GROUP BY 절은 GROUP BY 절의 expression에서 구분되지 않는 값이 있는 테이블의 행을 그룹화합니다. expression에 구분되지 않는 값이 있는 소스 테이블의 행이 여러 개인 경우 GROUP BY 절은 결합된 단일 행을 생성합니다. GROUP BY는 집계 함수가 SELECT 목록에 있거나 출력의 중복성을 제거할 때 주로 사용됩니다. expression의 데이터 유형은 그룹화 가능이어야 합니다.

예:

SELECT SUM(PointsScored), LastName
FROM PlayerStats
GROUP BY LastName;

GROUP BY 절은 SELECT 목록의 표현식 이름을 참조할 수 있습니다. 또한 GROUP BY 절은 정수 값을 사용하는 SELECT 목록의 표현식에 대한 서수 참조도 허용합니다. 1SELECT 목록의 첫 번째 표현식을 참조하고 2는 두 번째 표현식을 참조합니다. 표현식 목록은 서수와 표현식 이름을 결합할 수 있습니다.

예:

SELECT SUM(PointsScored), LastName, FirstName
FROM PlayerStats
GROUP BY LastName, FirstName;

위 쿼리는 다음과 같습니다.

SELECT SUM(PointsScored), LastName, FirstName
FROM PlayerStats
GROUP BY 2, FirstName;

또한 GROUP BY 절은 별칭을 참조할 수 있습니다. 쿼리에 SELECT 절의 별칭이 포함되어 있으면 이 별칭은 해당 FROM 절의 이름을 재정의합니다.

예를 들면 다음과 같습니다.

SELECT SUM(PointsScored), LastName as last_name
FROM PlayerStats
GROUP BY last_name;

HAVING 절

구문

HAVING bool_expression

HAVING 절은 WHERE 절과 유사합니다. bool_expression에 대해 평가될 때 TRUE를 반환하지 않는 행을 필터링합니다.

WHERE 절과 마찬가지로 bool_expression은 부울을 반환하는 표현식일 수 있으며 하위 조건 여러 개를 포함할 수 있습니다.

HAVING 절은 다음과 같은 점에서 WHERE 절과 다릅니다.

  • HAVING 절을 사용하려면 GROUP BY 또는 쿼리에 있는 집계가 필요합니다.
  • HAVING 절은 GROUP BY 및 집계 이후 그리고 ORDER BY 이전에 발생합니다. 즉, HAVING 절은 결과 조합에서 집계된 행마다 1번만 평가됩니다. 이 점이 GROUP BY 및 집계 이전에 평가되는 WHERE 절과 다릅니다.

HAVING 절은 SELECT 목록 별칭뿐만 아니라 FROM 절을 통해 사용할 수 있는 열을 참조할 수 있습니다. HAVING 절에서 참조되는 표현식은 GROUP BY 절에 나타나거나 집계 함수의 결과여야 합니다.

SELECT LastName
FROM Roster
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

쿼리에 SELECT 절의 별칭이 포함되어 있으면 이 별칭이 FROM 절의 이름을 재정의합니다.

SELECT LastName, SUM(PointsScored) AS ps
FROM Roster
GROUP BY LastName
HAVING ps > 0;

필수 집계

집계는 HAVING 절 자체에 있을 필요는 없지만 적어도 다음 형식 중 한 형식으로 있어야 합니다.

SELECT 목록의 집계 함수

SELECT LastName, SUM(PointsScored) AS total
FROM PlayerStats
GROUP BY LastName
HAVING total > 15;

'HAVING' 절의 집계 함수

SELECT LastName
FROM PlayerStats
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

SELECT 목록 및 HAVING 절의 집계

집계 함수가 SELECT 목록과 HAVING 절 모두에 있는 경우 집계 함수와 이들이 참조하는 열이 같을 필요는 없습니다. 아래 예시에서 COUNT()SUM()의 두 집계 함수는 서로 다르며 또한 서로 다른 열을 사용합니다.

SELECT LastName, COUNT(*)
FROM PlayerStats
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

ORDER BY 절

구문

ORDER BY expression
  [{ ASC | DESC }]
  [, ...]

ORDER BY 절은 열 또는 표현식을 결과 집합의 정렬 기준으로 지정합니다. ORDER BY 절이 없으면 쿼리 결과 순서는 정의되지 않습니다. FROM 절 또는 SELECT 목록의 열 별칭이 허용됩니다. 쿼리에 SELECT 절의 별칭이 포함되어 있으면 이 별칭은 해당 FROM 절의 이름을 재정의합니다.

옵션 절

  • ASC | DESC: expression 값의 오름차순 또는 내림차순으로 결과를 정렬합니다. ASC가 기본값입니다.

예시

기본 정렬 순서를 사용합니다(오름차순).

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true)
ORDER BY x;
+------+-------+
| x    | y     |
+------+-------+
| 1    | true  |
| 9    | true  |
+------+-------+

내림차순 정렬 순서를 사용합니다.

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true)
ORDER BY x DESC;
+------+-------+
| x    | y     |
+------+-------+
| 9    | true  |
| 1    | true  |
+------+-------+

여러 열을 기준으로 정렬할 수 있습니다. 아래 예시에서 결과 조합은 먼저 SchoolID로 정렬된 후 LastName으로 정렬됩니다.

SELECT LastName, PointsScored, OpponentID
FROM PlayerStats
ORDER BY SchoolID, LastName;

값 정렬 시 다음 규칙이 적용됩니다.

  • NULL: ORDER BY 절의 컨텍스트에서 NULL은 최소 가능 값입니다. 즉, ASC 정렬에서는 NULL이 가장 먼저 나타나고 DESC 정렬에서는 마지막으로 나타납니다.
  • 부동 소수점 데이터 유형: 정렬 및 그룹화는 부동 소수점 시맨틱스를 참조하세요.

집합 연산자와 함께 사용하면 ORDER BY 절은 가장 가까운 SELECT 문에만 적용되는 것이 아니라 전체 쿼리의 결과 조합에 적용됩니다. 따라서 괄호를 사용하여 ORDER BY 범위를 표시하는 것이 유용할 수 있습니다(필수는 아님).

다음 쿼리는 괄호 없는 쿼리입니다.

SELECT * FROM Roster
UNION ALL
SELECT * FROM TeamMascot
ORDER BY SchoolID;

위 쿼리는 괄호를 사용한 다음 쿼리와 동일합니다.

( SELECT * FROM Roster
  UNION ALL
  SELECT * FROM TeamMascot )
ORDER BY SchoolID;

하지만 ORDER BY 절이 두 번째 SELECT 문에만 적용되는 다음 쿼리와는 다릅니다.

SELECT * FROM Roster
UNION ALL
( SELECT * FROM TeamMascot
  ORDER BY SchoolID );

또한 ORDER BY 절에서 정수 리터럴을 열 참조로 사용할 수 있습니다. 정수 리터럴은 SELECT 목록의 서수(예: 1부터 카운트 시작)가 됩니다.

예시 - 다음 두 쿼리는 동일합니다.

SELECT SUM(PointsScored), LastName
FROM PlayerStats
ORDER BY LastName;
SELECT SUM(PointsScored), LastName
FROM PlayerStats
ORDER BY 2;

COLLATE

COLLATE 절을 사용하여 ORDER BY 절에서 데이터가 정렬되는 방식을 구체화할 수 있습니다. 대조란 특정 언어, 지역, 국가의 관습과 표준에 따라 문자열이 비교되는 방식을 결정하는 규칙 집합입니다. 이러한 규칙은 올바른 문자 순서 및 대소문자 구분 여부를 정의할 수 있습니다.

참고: COLLATE는 유형이 문자열인 열에만 사용할 수 있습니다.

문에 대조를 추가하는 방법은 다음과 같습니다.

SELECT ...
FROM ...
ORDER BY value COLLATE collation_string

collation_stringcollation_name을 포함하며, 선택적으로 콜론으로 구분된 collation_attribute 서픽스를 가질 수 있습니다. collation_string은 리터럴 또는 매개변수입니다. 일반적으로 이 이름은 언어를 나타내는 2자리 문자이며, 선택적으로 밑줄과 함께 지역을 나타내는 2자리 문자가 추가될 수 있습니다(예: en_US). 이러한 이름은 Common Locale Data Repository(CLDR)에 의해 정의됩니다. 문의 collation_nameunicode일 수도 있습니다. 이 값은 명령문이 기본 유니코드 대조를 사용하여 데이터를 반환해야 함을 나타냅니다.

collation_stringcollation_name 이외에 선택적으로 콜론으로 구분된 collation_attribute 서픽스를 가질 수 있습니다. 이 속성은 데이터 비교 시 대소문자를 구분할지 여부를 지정합니다. 허용되는 값은 cs(대소문자를 구분함) 및 ci(대소문자를 구분하지 않음)입니다. collation_attribute를 지정하지 않으면 CLDR 기본값이 사용됩니다.

COLLATE 예시

캐나다 영어를 사용하여 결과 대조:

SELECT Place
FROM Locations
ORDER BY Place COLLATE "en_CA"

매개변수를 사용하여 결과 대조:

#@collate_param = "arg_EG"
SELECT Place
FROM Locations
ORDER BY Place COLLATE @collate_param

명령문 하나에 여러 COLLATE 절 사용:

SELECT APlace, BPlace, CPlace
FROM Locations
ORDER BY APlace COLLATE "en_US" ASC,
         BPlace COLLATE "ar_EG" DESC,
         CPlace COLLATE "en" DESC

대소문자를 구분하지 않고 대조:

SELECT Place
FROM Locations
ORDER BY Place COLLATE "en_US:ci"

기본 유니코드로 대소문자를 구분하지 않고 대조:

SELECT Place
FROM Locations
ORDER BY Place COLLATE "unicode:ci"

집합 연산자

구문

UNION { ALL | DISTINCT } | INTERSECT { ALL | DISTINCT } | EXCEPT { ALL | DISTINCT }

집합 연산자는 입력 쿼리 결과 두 개 이상을 단일 결과 조합으로 결합합니다. ALL 또는 DISTINCT를 지정해야 합니다. ALL을 지정하면 모든 행이 유지됩니다. DISTINCT를 지정하면 중복 행이 삭제됩니다.

다음은 지정된 R 행이 첫 번째 입력 쿼리에서 정확히 m번 나타나고 두 번째 입력 쿼리에서 n번 나타나는 경우(m > = 0, n > = 0)입니다.

  • UNION ALL의 경우 R은 결과에 정확히 m + n번 나타납니다.
  • INTERSECT ALL의 경우 R은 결과에 정확히 `MIN(m, n)`번 나타납니다.
  • EXCEPT ALL의 경우 R은 결과에 정확히 `MAX(m - n, 0)`번 나타납니다.
  • UNION DISTINCT의 경우 DISTINCTUNION이 계산된 후 계산되므로 R은 정확히 한 번 나타납니다.
  • INTERSECT DISTINCT의 경우 DISTINCT는 위의 결과가 계산된 후에 계산됩니다.
  • EXCEPT DISTINCT의 경우 m > 0 및 n = 0이면 R 행은 출력에 한 번 나타납니다.
  • 입력 쿼리가 두 개 이상 있는 경우 위 연산이 일반화되며 출력은 입력이 왼쪽에서 오른쪽으로 점진적으로 결합된 경우와 동일합니다.

다음 규칙이 적용됩니다.

  • UNION ALL 이외의 집합 연산인 경우 모든 열 유형이 동등 비교를 지원해야 합니다.
  • 연산자 양쪽의 입력 쿼리는 열을 같은 개수로 반환해야 합니다.
  • 연산자는 각 입력 쿼리에서 반환된 열을 각 SELECT 목록의 열 위치에 따라 쌍으로 만듭니다. 즉, 첫 번째 입력 쿼리의 첫 번째 열과 두 번째 입력 쿼리의 첫 번째 열을 쌍으로 만듭니다.
  • 결과 조합은 항상 첫 번째 입력 쿼리의 열 이름을 사용합니다.
  • 결과 조합은 항상 해당 열에서 입력 유형의 상위 유형을 사용하므로 쌍을 이룬 열 또한 동일한 데이터 유형이나 공통 상위 유형을 가져야 합니다.
  • 괄호를 사용하여 서로 다른 집합 연산을 구분해야 합니다. 따라서 UNION ALLUNION DISTINCT 등의 집합 연산자는 서로 다릅니다. 문이 동일한 집합 연산만 반복하는 경우에는 괄호가 필요하지 않습니다.

예:

query1 UNION ALL (query2 UNION DISTINCT query3)
query1 UNION ALL query2 UNION ALL query3

잘못된 경우:

query1 UNION ALL query2 UNION DISTINCT query3
query1 UNION ALL query2 INTERSECT ALL query3;  // INVALID.

UNION

UNION 연산자는 각 쿼리의 결과 조합에 있는 열을 쌍으로 만들고 이를 세로로 연결하여 두 개 이상의 입력 쿼리 결과 조합을 결합합니다.

INTERSECT

INTERSECT 연산자는 왼쪽 및 오른쪽 입력 쿼리의 결과 조합에서 발견된 행을 반환합니다. EXCEPT와 달리 입력 쿼리의 위치(INTERSECT 연산자의 왼쪽 또는 오른쪽)는 중요하지 않습니다.

EXCEPT

EXCEPT 연산자는 왼쪽 입력 쿼리에서 오른쪽 입력 쿼리에 없는 행을 반환합니다.

예를 들면 다음과 같습니다.

SELECT * FROM UNNEST(ARRAY<int64>[1, 2, 3]) AS number
EXCEPT DISTINCT SELECT 1;

+--------+
| number |
+--------+
| 2      |
| 3      |
+--------+

LIMIT 절과 OFFSET 절

구문

LIMIT count [ OFFSET skip_rows ]

LIMIT는 INT64 유형의 음수가 아닌 count를 지정하며, count 이하의 행이 반환됩니다. LIMIT 0은 행을 0개 반환합니다.

집합 연산이 있으면 집합 연산이 평가된 후에 LIMIT가 적용됩니다.

OFFSETLIMIT을 적용하기 전에 건너뛸 행 수를 지정합니다. 이때 이 수는 음수가 아닌 값입니다. skip_rows는 INT64 유형입니다.

이 절은 리터럴 또는 매개변수 값만 허용합니다. LIMITOFFSET에서 반환된 행은 ORDER BY 이후에 이러한 연산자가 사용되는 경우에만 지정됩니다.

예:

SELECT *
FROM UNNEST(ARRAY<STRING>['a', 'b', 'c', 'd', 'e']) AS letter
ORDER BY letter ASC LIMIT 2

+---------+
| letter  |
+---------+
| a       |
| b       |
+---------+
SELECT *
FROM UNNEST(ARRAY<STRING>['a', 'b', 'c', 'd', 'e']) AS letter
ORDER BY letter ASC LIMIT 3 OFFSET 1

+---------+
| letter  |
+---------+
| b       |
| c       |
| d       |
+---------+

WITH 절

WITH 절은 하나 이상의 명명된 서브 쿼리 결과를 임시 테이블 이름에 바인딩합니다. 사용된 각 테이블 이름은 동일한 쿼리 표현식 내의 이후 SELECT 표현식에 표시됩니다. 여기에는 다음과 같은 종류의 SELECT 표현식이 포함됩니다.

  • 이후 WITH 바인딩의 모든 SELECT 표현식
  • UNION과 같은 집합 연산자의 양쪽에 있는 쿼리 표현식의 최상위 SELECT 표현식
  • 동일한 쿼리 표현식 내의 서브 쿼리 내부 SELECT 표현식

예:

WITH subQ1 AS (SELECT SchoolID FROM Roster),
     subQ2 AS (SELECT OpponentID FROM PlayerStats)
SELECT * FROM subQ1
UNION ALL
SELECT * FROM subQ2;

서브 쿼리 내에서는 WITH가 지원되지 않습니다. 그런 경우 오류가 반환됩니다.

SELECT account
FROM (
  WITH result AS (SELECT * FROM NPCs)
  SELECT *
  FROM result);

WITH RECURSIVE는 지원되지 않습니다.

WITH 절은 DML 문에서 지원되지 않습니다.

WITH 절로 정의된 임시 테이블은 메모리에 저장됩니다. Cloud Spanner SQL은 쿼리로 생성된 모든 임시 테이블에 대해 메모리를 동적으로 할당합니다. 사용 가능한 리소스가 충분하지 않으면 쿼리가 실패합니다.

별칭 사용

별칭은 쿼리에 있는 테이블, 열 또는 표현식에 제공되는 임시 이름입니다. SELECT 목록 또는 FROM 절에 명시적 별칭을 사용할 수 있습니다. 또는 Cloud Spanner SQL이 일부 표현식에 대해 암시적 별칭을 유추합니다. 명시적 또는 암시적 별칭이 없는 표현식은 익명이며 쿼리가 이름으로 별칭을 참조할 수 없습니다.

명시적 별칭 구문

FROM 절 또는 SELECT 목록에 명시적 별칭을 사용할 수 있습니다.

FROM 절에서 [AS] alias를 사용하면 테이블, 배열, 서브 쿼리, UNNEST 절을 포함한 모든 항목에 명시적 별칭을 사용할 수 있습니다. AS 키워드는 선택사항입니다.

예:

SELECT s.FirstName, s2.SongName
FROM Singers AS s, (SELECT * FROM Songs) AS s2;

[AS] alias를 사용하면 SELECT 목록의 모든 표현식에 명시적 별칭을 사용할 수 있습니다. AS 키워드는 선택사항입니다.

예:

SELECT s.FirstName AS name, LOWER(s.FirstName) AS lname
FROM Singers s;

명시적 별칭 공개

쿼리에 명시적 별칭을 도입하면 쿼리에서 해당 별칭을 참조할 수 있는 다른 위치가 제한됩니다. Cloud Spanner SQL의 이름 범위 지정 규칙으로 인해 별칭 표시 여부가 제한됩니다.

FROM 절 별칭

Cloud Spanner SQL은 FROM 절의 별칭을 왼쪽에서 오른쪽으로 처리합니다. 별칭은 FROM 절의 후속 경로 표현식에만 표시됩니다.

예를 들면 다음과 같습니다.

Singers 테이블에 ARRAY 유형의 Concerts 열이 있다고 가정합니다.

SELECT FirstName
FROM Singers AS s, s.Concerts;

잘못된 경우:

SELECT FirstName
FROM s.Concerts, Singers AS s;  // INVALID.

FROM 절 별칭은 동일한 FROM 절의 서브 쿼리에 표시되지 않습니다. FROM 절의 서브 쿼리에는 동일한 FROM 절의 다른 테이블에 대한 상호 참조가 포함될 수 없습니다.

잘못된 경우:

SELECT FirstName
FROM Singers AS s, (SELECT (2020 - ReleaseDate) FROM s)  // INVALID.

테이블 이름에 대한 자격 여부에 관계없이 FROM에 있는 테이블의 열 이름을 쿼리의 모든 위치에서 별칭으로 사용할 수 있습니다.

예:

SELECT FirstName, s.ReleaseDate
FROM Singers s WHERE ReleaseDate = 1975;

FROM 절에 명시적 별칭이 있는 경우 쿼리의 나머지 부분에 대한 암시적 별칭 대신 이 명시적 별칭을 사용해야 합니다(암시적 별칭 참조). 테이블 별칭은 쿼리 처리 시 동일한 테이블을 여러 번 검사하는 자체 조인과 같은 경우에 모호성을 없애거나 간단하게 나타내는 데 사용될 수 있습니다.

예:

SELECT * FROM Singers as s, Songs as s2
ORDER BY s.LastName

잘못된 경우 — ORDER BY가 테이블 별칭을 사용하지 않음:

SELECT * FROM Singers as s, Songs as s2
ORDER BY Singers.LastName;  // INVALID.

SELECT 목록 별칭

SELECT 목록의 별칭은 다음 절에만 표시됩니다.

  • GROUP BY
  • ORDER BY
  • HAVING

예:

SELECT LastName AS last, SingerID
FROM Singers
ORDER BY last;

GROUP BY, ORDER BY, HAVING 절의 명시적 별칭

GROUP BY, ORDER BY, HAVING의 세 가지 절은 다음 값만 참조할 수 있습니다.

  • FROM 절의 테이블과 해당 열
  • SELECT 목록의 별칭

또한 GROUP BYORDER BY는 세 번째 그룹을 참조할 수 있습니다.

  • SELECT 목록의 항목을 참조하는 정수 리터럴. 정수 1SELECT 목록의 첫 번째 항목을 참조하고 2는 두 번째 항목을 참조합니다.

예:

SELECT SingerID AS sid, COUNT(Songid) AS s2id
FROM Songs
GROUP BY 1
ORDER BY 2 DESC;

위 쿼리는 다음과 같습니다.

SELECT SingerID AS sid, COUNT(Songid) AS s2id
FROM Songs
GROUP BY sid
ORDER BY s2id DESC;

모호한 별칭

이름이 모호한 경우 Cloud Spanner SQL에서 오류가 발생하며, 이는 하나 이상의 고유 객체로 해석될 수 있다는 의미입니다.

예:

SingersSongs 모두에 SingerID라는 열이 있으므로 이 쿼리에는 테이블 사이에서 충돌하는 열 이름이 있는 것입니다.

SELECT SingerID
FROM Singers, Songs;

이 쿼리는 SELECT 목록에서 중복뒤므로 GROUP BY 절로는 모호한 별칭이 포함되어 있습니다.

SELECT FirstName AS name, LastName AS name,
FROM Singers
GROUP BY name;

이 쿼리는 이름이 동일하여 SELECT 목록과 FROM 절로는 모호한 별칭이 포함되어 있습니다. tablex, y, z 열이 있다고 가정합시다. z는 STRUCT 유형이며 v, w, x 필드가 있습니다.

예를 들면 다음과 같습니다.

SELECT x, z AS T
FROM table AS T
GROUP BY T.x;

별칭 T는 모호하며 GROUP BY 절의 T.xtable.x 또는 table.z.x를 참조할 수 있으므로 오류가 발생합니다.

열 이름이면서 SELECT 목록 별칭인 이름은 동일한 기본 객체로 확인되기만 한다면 GROUP BY, ORDER BY 또는 HAVING에서 모호하지 않습니다.

예:

SELECT LastName, BirthYear AS BirthYear
FROM Singers
GROUP BY BirthYear;

별칭 BirthYear는 동일한 기본 열인 Singers.BirthYear로 확인되므로 모호하지 않습니다.

암시적 별칭

SELECT 목록에서 명시적 별칭이 없는 표현식이 있으면 Cloud Spanner SQL은 다음 규칙을 따라 암시적 별칭을 할당합니다. SELECT 목록에는 동일한 별칭을 가진 열이 여러 개 있을 수 있습니다.

  • 식별자의 경우 별칭은 식별자입니다. 예를 들어 SELECT abcAS abc를 암시합니다.
  • 경로 표현식의 경우 별칭은 경로의 마지막 식별자입니다. 예를 들어 SELECT abc.def.ghiAS ghi을 암시합니다.
  • 'dot' 구성원 필드 액세스 연산자를 사용하는 필드 액세스의 경우 별칭은 필드 이름입니다. 예를 들어 SELECT (struct_function()).fnameAS fname을 암시합니다.

다른 모든 경우에는 암시적 별칭이 없으므로 열은 익명이며 이름으로 참조될 수 없습니다. 이러한 열의 데이터는 계속 반환되며 표시된 쿼리 결과에 이러한 열에 대해 생성된 라벨이 있을 수 있지만 별칭처럼 사용될 수 없습니다.

FROM 절에서 from_item은 별칭을 가질 필요가 없습니다. 다음 규칙이 적용됩니다.

  • 명시적 별칭이 없는 표현식이 있는 경우 Cloud Spanner SQL은 다음과 같은 경우 암시적 별칭을 할당합니다.
    • 식별자의 경우 별칭은 식별자입니다. 예를 들어 FROM abcAS abc를 암시합니다.
    • 경로 표현식의 경우 별칭은 경로의 마지막 식별자입니다. 예를 들어 FROM abc.def.ghiAS ghi를 암시합니다.
    • WITH OFFSET을 통해 생성된 열에는 암시적 별칭 offset이 있습니다.

  • 테이블 서브 쿼리에는 암시적 별칭이 없습니다.
  • FROM UNNEST(x)에는 암시적 별칭이 없습니다.

부록 A: 샘플 데이터가 있는 예시

이러한 예시에는 Roster, TeamMascot, PlayerStats 테이블에서 쿼리를 수행하는 구문이 포함됩니다.

GROUP BY 절

예:

SELECT LastName, SUM(PointsScored)
FROM PlayerStats
GROUP BY LastName;
LastName SUM
Adams 7
Buchanan 13
Coolidge 1

집합 연산자

UNION

UNION 연산자는 각 SELECT 문의 결과 조합에 있는 열을 쌍으로 만들고 이를 세로로 연결하여 SELECT 문 두 개 이상의 결과 조합을 결합합니다.

예:

SELECT Mascot AS X, SchoolID AS Y
FROM TeamMascot
UNION ALL
SELECT LastName, PointsScored
FROM PlayerStats;

결과:

X Y
Jaguars 50
Knights 51
Lakers 52
Mustangs 53
Adams 3
Buchanan 0
Coolidge 1
Adams 4
Buchanan 13

INTERSECT

이 쿼리는 Roster와 PlayerStats 모두에 있는 성을 반환합니다.

SELECT LastName
FROM Roster
INTERSECT ALL
SELECT LastName
FROM PlayerStats;

결과:

LastName
Adams
Coolidge
Buchanan

EXCEPT

아래 쿼리는 PlayerStats에는 없고 Roster에만 있는 성을 반환합니다.

SELECT LastName
FROM Roster
EXCEPT DISTINCT
SELECT LastName
FROM PlayerStats;

결과:

LastName
Eisenhower
Davis

SELECT 문 순서를 반대로 하면 Roster에는 없고 PlayerStats에 있는 성이 반환됩니다.

SELECT LastName
FROM PlayerStats
EXCEPT DISTINCT
SELECT LastName
FROM Roster;

결과:

(empty)