서브 쿼리

서브 쿼리 정보

서브 쿼리는 다른 쿼리 문 안에 나타나는 쿼리입니다. 서브 쿼리를 하위 SELECT 또는 중첩된 SELECT라고도 합니다. 전체 SELECT 구문이 서브 쿼리에서 유효합니다.

서브 쿼리에서는 WITH 절이 지원되지 않습니다. 그렇지 않으면 오류가 반환됩니다.

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

표현식 서브 쿼리

표현식 서브 쿼리는 표현식이 유효한 모든 쿼리에서 사용되며, 열이나 테이블이 아닌 단일 값을 반환합니다. 표현식 서브 쿼리는 상관 관계가 있을 수 있습니다.

스칼라 서브 쿼리

( subquery )

설명

표현식 내의 서브 쿼리는 스칼라 서브 쿼리로 해석됩니다. 스칼라 서브 쿼리는 SELECT 목록 또는 WHERE 절에서 종종 사용됩니다.

스칼라 서브 쿼리는 단일 열을 선택해야 합니다. 여러 열을 선택하려고 하면 분석 오류가 발생합니다. 단일 표현식이 있는 SELECT 목록은 단일 열을 선택하는 가장 간단한 방식입니다. 스칼라 서브 쿼리의 결과 유형은 해당 표현식의 유형입니다.

또 다른 방법은 SELECT AS STRUCT를 사용하여 하나 이상의 표현식으로 정의된 필드가 포함된 단일 STRUCT 유형 값을 선택하는 서브 쿼리를 정의하는 것입니다.

서브 쿼리가 정확하게 행 한 개만 반환할 경우 이 단일 값이 스칼라 서브 쿼리 결과입니다. 서브 쿼리가 0개의 행을 반환할 경우 결과는 NULL입니다. 서브 쿼리가 행을 두 개 이상 반환할 경우 쿼리가 런타임 오류와 함께 실패합니다.

예시

이 예시에서는 상관 스칼라 서브 쿼리가 PlayersGuilds 테이블을 사용하여 플레이어 목록의 마스코트를 반환합니다.

SELECT account, (SELECT mascot FROM Guilds WHERE Players.guild = id) AS player_mascot
FROM Players;

+---------------------------+
| account   | player_mascot |
+---------------------------+
| gorbie    | cardinal      |
| junelyn   | finch         |
| corba     | parrot        |
+---------------------------+

이 예시에서는 집계 스칼라 서브 쿼리가 Players 테이블에 있는 사용자 계정의 평균 수준 avg_level을 계산합니다.

SELECT account, level, (SELECT AVG(level) FROM Players) AS avg_level
FROM Players;

+---------------------------------------+
| account   | level      | avg_level    |
+---------------------------------------+
| gorbie    | 29         | 24.66        |
| junelyn   | 2          | 24.66        |
| corba     | 43         | 24.66        |
+---------------------------------------+

배열 서브 쿼리

ARRAY ( subquery )

설명

배열 서브 쿼리는 ARRAY를 반환한다는 점에서 특수한 표현식 서브 쿼리입니다. 서브 쿼리가 0개의 행을 반환하면 빈 ARRAY를 반환합니다. 절대 NULL ARRAY를 반환하지 않습니다.

배열 서브 쿼리의 SELECT 목록에는 배열 서브 쿼리에서 반환된 배열의 요소 유형을 정의하는 모든 유형의 열이 정확히 한 개 있어야 합니다. 그렇지 않으면 오류가 반환됩니다. 서브 쿼리가 SELECT AS STRUCT로 작성된 경우에는 SELECT 목록에 여러 열이 포함될 수 있으며 배열 서브 쿼리에서 반환되는 값은 생성된 STRUCT의 ARRAY입니다. SELECT AS를 사용하지 않고 열을 여러 개 선택하면 오류가 발생합니다.

배열 서브 쿼리는 SELECT AS STRUCT를 사용하여 구조체의 배열을 빌드할 수 있습니다.

전체 시맨틱스는 배열 함수를 참조하세요.

예시

이 예시에서 배열 서브 쿼리는 NPCs 테이블의 빨간색 길드에 할당된 계정 배열을 반환합니다.

SELECT ARRAY(SELECT account FROM NPCs WHERE guild = 'red') as red
FROM NPCs LIMIT 1;

+-----------------+
| red             |
+-----------------+
| [niles,jujul]   |
+-----------------+

IN 서브 쿼리

value [ NOT ] IN ( subquery )

설명

value가 서브 쿼리에서 반환된 행 집합에 있으면 TRUE를 반환합니다. 서브 쿼리가 행을 0개 반환할 경우 FALSE를 반환합니다.

서브 쿼리의 SELECT 목록은 모든 유형의 단일 열을 가져야 하며 해당 유형은 value의 유형과 비교가 가능해야 합니다. 그렇지 않으면 오류가 반환됩니다. NULL 처리를 포함한 전체 시맨틱스는 IN 연산자를 참조하세요.

배열에 IN 서브 쿼리를 사용해야 하는 경우 다음은 동일합니다.

value [ NOT ] IN ( subquery )
value [ NOT ] IN UNNEST( ARRAY( subquery ) )

예시

이 예시에서는 IN 연산자가 corba라는 계정이 Players 테이블 내에 존재하는지 확인합니다.

SELECT "corba" IN (SELECT account FROM Players) as result;

+--------+
| result |
+--------+
| TRUE   |
+--------+

EXISTS 서브 쿼리

EXISTS ( subquery )

설명

서브 쿼리가 하나 이상의 행을 생성하는 경우 TRUE를 반환합니다. 서브 쿼리가 0개의 행을 생성하는 경우 FALSE를 반환합니다. 절대 NULL을 반환하지 않습니다. 다른 모든 표현식 서브 쿼리와 달리, 열 목록에 대한 규칙이 없습니다. 원하는 개수의 열을 선택할 수 있으며, 쿼리 결과는 이에 영향을 받지 않습니다.

예시

이 예시에서 EXISTS 연산자는 Players 테이블을 사용하여 생성된 행이 있는지 확인합니다.

SELECT EXISTS(SELECT account FROM Players WHERE guild="yellow") as result;

+--------+
| result |
+--------+
| FALSE  |
+--------+

테이블 서브 쿼리

FROM ( subquery ) [ [ AS ] alias ]

설명

테이블 서브 쿼리를 사용하면 외부 쿼리가 서브 쿼리의 결과를 테이블로 처리합니다. 테이블 서브 쿼리는 FROM 절에서만 사용할 수 있습니다.

예시

이 예시에서는 서브 쿼리가 Players 테이블에서 계정 테이블을 반환합니다.

SELECT results.account
FROM (SELECT * FROM Players) AS results;

+-----------+
| account   |
+-----------+
| gorbie    |
| junelyn   |
| corba     |
+-----------+

상관 하위 쿼리

상관 서브 쿼리는 해당 서브 쿼리 외부의 열을 참조하는 서브 쿼리입니다. 상관 관계는 서브 쿼리 결과를 재사용하는 것을 방지합니다. 자세한 내용을 여기에서 알아볼 수 있습니다.

예시

이 예시에서는 할당된 플레이어가 없는 마스코트 목록이 반환됩니다. GuildsPlayers 테이블이 참조됩니다.

SELECT mascot
FROM Guilds
WHERE NOT EXISTS (SELECT account
  FROM Players
  WHERE Guilds.id = Players.guild)

+----------+
| mascot   |
+----------+
| sparrow  |
+----------+

이 예시에서는 상관 스칼라 서브 쿼리가 PlayersGuilds 테이블을 사용하여 플레이어 목록의 마스코트를 반환합니다.

SELECT account, (SELECT mascot FROM Guilds WHERE Players.guild = id) AS player_mascot
FROM Players;

+---------------------------+
| account   | player_mascot |
+---------------------------+
| gorbie    | cardinal      |
| junelyn   | finch         |
| corba     | parrot        |
+---------------------------+

휘발성 서브 쿼리

휘발성 서브 쿼리는 동일한 입력에 대해 항상 동일한 결과를 생성하지 않는 서브 쿼리입니다. 예를 들어 서브 쿼리에 난수를 반환하는 함수가 포함된 경우, 결과가 항상 동일하지 않으므로 서브 쿼리는 휘발성입니다.

예시

이 예시에서는 Players 테이블에서 무작위 수의 계정이 반환됩니다.

SELECT results.account
FROM (SELECT * FROM Players WHERE RAND() < 0.5) AS results;

-- The results are not always the same when you execute
-- the preceding query, but will look similar to this:
+---------+
| account |
+---------+
| gorbie  |
| junelyn |
+---------+

서브 쿼리에 대한 평가 규칙

일부 서브 쿼리는 한 번 평가되며 다른 서브 쿼리는 더 자주 평가됩니다.

  • 쿼리 계획에 따라 서로 관련이 없는 휘발성 서브 쿼리가 행당 한 번씩 재평가될 수 있습니다.
  • 상관 서브 쿼리는 모든 고유한 매개변수 값 집합에 대해 논리적으로 재평가되어야 합니다. 쿼리 계획에 따라 여러 행에 동일한 매개변수 값이 있더라도 행당 하나의 상관 서브 쿼리가 다시 평가될 수 있습니다.
  • WITH로 임시 테이블에 할당된 서브 쿼리는 'as-if'로 한 번 평가됩니다. 쿼리 계획은 서브 쿼리가 다시 평가될 때마다 같은 테이블을 생성할 경우에만 다시 평가할 수 있습니다.

예시에 사용된 공통 테이블

일부 예시에서는 Players라는 테이블을 참조합니다.

+-----------------------------+
| account   | level   | guild |
+-----------------------------+
| gorbie    | 29      | red   |
| junelyn   | 2       | blue  |
| corba     | 43      | green |
+-----------------------------+

일부 예시에서는 NPCs라는 테이블을 참조합니다.

+-------------------+
| account   | guild |
+-------------------+
| niles     | red   |
| jujul     | red   |
| effren    | blue  |
+-------------------+

일부 예시에서는 Guilds라는 테이블을 참조합니다.

+-------------------+
| mascot   | id     |
+-------------------+
| cardinal | red    |
| parrot   | green  |
| finch    | blue   |
| sparrow  | yellow |
+-------------------+

WITH 절을 사용하여 WITH 절을 지원하는 서브 쿼리에서 PlayersNPCs에 대한 임시 테이블 이름을 에뮬레이션할 수 있습니다.

WITH
  Players AS (
    SELECT 'gorbie' AS account, 29 AS level, 'red' AS guild UNION ALL
    SELECT 'junelyn', 2 , 'blue' UNION ALL
    SELECT 'corba', 43, 'green'),
  NPCs AS (
    SELECT 'niles' AS account, 'red' AS guild UNION ALL
    SELECT 'jujul', 'red' UNION ALL
    SELECT 'effren', 'blue'),
  Guilds AS (
    SELECT 'cardinal' AS mascot , 'red' AS id UNION ALL
    SELECT 'parrot', 'green' UNION ALL
    SELECT 'finch', 'blue' UNION ALL
    SELECT 'sparrow', 'yellow')
SELECT * FROM (
  SELECT account, guild FROM Players UNION ALL
  SELECT account, guild FROM NPCs)