

 Amazon Redshift는 패치 198부터 새 Python UDF 생성을 더 이상 지원하지 않습니다. 기존 Python UDF는 2026년 6월 30일까지 계속 작동합니다. 자세한 내용은 [블로그 게시물](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)을 참조하세요.

# SELECT
<a name="r_SELECT_synopsis"></a>

테이블, 뷰 및 사용자 정의 함수에서 행을 반환합니다.

**참고**  
단일 SQL 문의 최대 크기는 16MB입니다.

## 구문
<a name="r_SELECT_synopsis-synopsis"></a>

```
[ WITH with_subquery [, ...] ]
SELECT
[ TOP number | [ ALL | DISTINCT ]
* | expression [ AS output_name ] [, ...] ]
[ EXCLUDE column_list ]
[ FROM table_reference [, ...] ]
[ WHERE condition ]
[ [ START WITH expression ] CONNECT BY expression ]
[ GROUP BY ALL | expression [, ...] ]
[ HAVING condition ]
[ QUALIFY condition ]
[ { UNION | ALL | INTERSECT | EXCEPT | MINUS } query ]
[ ORDER BY expression [ ASC | DESC ] ]
[ LIMIT { number | ALL } ]
[ OFFSET start ]
```

**Topics**
+ [구문](#r_SELECT_synopsis-synopsis)
+ [WITH 절](r_WITH_clause.md)
+ [SELECT 목록](r_SELECT_list.md)
+ [EXCLUDE column\$1list](r_EXCLUDE_list.md)
+ [FROM 절](r_FROM_clause30.md)
+ [WHERE 절](r_WHERE_clause.md)
+ [GROUP BY 절](r_GROUP_BY_clause.md)
+ [HAVING 절](r_HAVING_clause.md)
+ [QUALIFY 절](r_QUALIFY_clause.md)
+ [UNION, INTERSECT 및 EXCEPT](r_UNION.md)
+ [ORDER BY 절](r_ORDER_BY_clause.md)
+ [CONNECT BY 절](r_CONNECT_BY_clause.md)
+ [하위 쿼리 예](r_Subquery_examples.md)
+ [상관관계가 있는 하위 쿼리](r_correlated_subqueries.md)

# WITH 절
<a name="r_WITH_clause"></a>

WITH 절은 쿼리에 있는 SELECT 목록에 선행하는 선택적 절입니다. WITH 절은 하나 이상의 *common\$1table\$1expressions*를 정의합니다. 각 공통 테이블 표현식(CTE) 은 뷰 정의와 유사한 임시 테이블을 정의합니다. FROM 절에서 이러한 임시 테이블을 참조할 수 있습니다. 임시 테이블은 자신이 속한 쿼리가 실행되는 동안에만 사용됩니다. WITH 절에 있는 각각의 CTE는 테이블 이름, 열 이름의 선택적 목록, 테이블로 평가되는 쿼리 표현식(SELECT 문)을 지정합니다. 임시 테이블 이름을 정의하는 동일한 쿼리 식의 FROM 절에서 임시 테이블 이름을 참조하는 경우 CTE는 재귀적입니다.

WITH 절 하위 쿼리는 단일 쿼리를 실행하는 내내 사용 가능한 테이블을 정의하는 효율적인 방법입니다. 모든 경우에 있어 SELECT 문의 본문에 하위 쿼리를 사용하여 같은 결과를 얻을 수 있지만, WITH 절 하위 쿼리는 더 간단하게 쓰고 읽을 수 있습니다. 가능한 경우 여러 번 참조되는 WITH 절 하위 쿼리는 공통 하위 표현식으로 최적화됩니다. 즉, WITH 하위 쿼리를 한 번 평가하고 그 결과를 재사용할 수 있습니다. (공통 하위 표현식은 WITH 절에 정의되는 하위 표현식으로 제한되지 않습니다.)

## 구문
<a name="r_WITH_clause-synopsis"></a>

```
[ WITH [RECURSIVE] common_table_expression [, common_table_expression , ...] ]
```

여기서 *common\$1table\$1expression*은 비재귀적이거나 재귀적일 수 있습니다. 다음은 비재귀 형식입니다.

```
CTE_table_name [ ( column_name [, ...] ) ] AS ( query )
```

다음은 *common\$1table\$1expression*의 재귀 형식입니다.

```
CTE_table_name (column_name [, ...] ) AS ( recursive_query )
```

## 파라미터
<a name="r_WITH_clause-parameters"></a>

 RECURSIVE   
쿼리를 재귀 CTE로 식별하는 키워드입니다. WITH 절에 정의된 *common\$1table\$1expression*이 재귀적이면 이 키워드가 필요합니다. WITH 절에 여러 재귀 CTE가 포함된 경우에도 WITH 키워드 바로 다음에 RECURSIVE 키워드를 한 번만 지정할 수 있습니다. 일반적으로 재귀 CTE는 두 부분으로 구성된 UNION ALL 하위 쿼리입니다.

 *common\$1table\$1expression*   
[FROM 절](r_FROM_clause30.md)에서 참조할 수 있는 임시 테이블을 정의하고 해당 테이블이 속한 쿼리 실행 중에만 사용됩니다.

 *CTE\$1table\$1name*   
WITH 절 하위 쿼리의 결과를 정의하는 임시 테이블의 고유한 이름입니다. 단일 WITH 절 내에서 중복되는 이름을 사용할 수 없습니다. 각각의 하위 쿼리에는 [FROM 절](r_FROM_clause30.md)에서 참조될 수 있는 테이블 이름이 주어져야 합니다.

 *column\$1name*   
 WITH 절 하위 쿼리에 대한 출력 열 이름의 목록으로, 쉼표로 구분됩니다. 지정되는 열 이름의 수는 하위 쿼리로 정의되는 열 개수보다 적거나 같아야 합니다. 비재귀 CTE의 경우 *column\$1name* 절은 옵션입니다. 재귀 CTE의 경우 *column\$1name* 목록은 필수입니다.

 *query*()   
 Amazon Redshift에서 지원하는 SELECT 쿼리입니다. [SELECT](r_SELECT_synopsis.md)을(를) 참조하세요.

 *recursive\$1query*   
2개의 SELECT 하위 쿼리로 구성된 UNION ALL 쿼리:  
+ 첫 번째 SELECT 하위 쿼리에는 동일한 *CTE\$1table\$1name*에 대한 재귀 참조가 없습니다. 재귀의 초기 시드인 결과 집합을 반환합니다. 이 부분을 초기 멤버 또는 시드 멤버라고 합니다.
+ 두 번째 SELECT 하위 쿼리는 FROM 절에서 동일한 *CTE\$1table\$1name*을 참조합니다. 이를 재귀 멤버라고합니다. *recursive\$1query*는 *recursive\$1query*를 종료하기 위한 WHERE 조건을 포함합니다.

## 사용 노트
<a name="r_WITH_clause-usage-notes"></a>

다음 SQL 문에 WITH 절을 사용할 수 있습니다.
+ SELECT 
+ SELECT INTO
+ CREATE TABLE AS
+ CREATE VIEW
+ DECLARE
+ EXPLAIN
+ INSERT INTO...SELECT 
+ PREPARE
+ UPDATE(WHERE 절 하위 쿼리 내. 하위 쿼리에서 재귀 CTE를 정의할 수 없습니다. 재귀 CTE는 UPDATE 절 앞에 와야 합니다.)
+ DELETE

WITH 절을 포함한 쿼리의 FROM 절이 WITH 절로 정의되는 테이블 중 참조하지 않는 테이블이 있을 경우 WITH 절이 무시되고 쿼리가 정상적으로 실행됩니다.

WITH 절 하위 쿼리로 정의되는 테이블은 WITH 절이 시작하는 SELECT 쿼리의 범위에서만 참조될 수 있습니다. 예를 들어, SELECT 목록, WHERE 절 또는 HAVING 절에 있는 하위 쿼리의 FROM 절에서 그와 같은 테이블을 참조할 수 있습니다. 하위 쿼리에 WITH 절을 사용할 수 없고 기본 쿼리 또는 다른 하위 쿼리의 FROM 절에서 WITH 절의 테이블을 참조할 수 없습니다. 이 쿼리 패턴으로 인해 WITH 절 테이블에 대해 `relation table_name doesn't exist` 형식의 오류 메시지가 발생합니다.

WITH 절 하위 쿼리 내에서 다른 WITH 절을 지정할 수 없습니다.

WITH 절 하위 쿼리에 의해 정의되는 테이블에 대한 전방 참조를 할 수 없습니다. 예를 들어, 다음 쿼리는 테이블 W1의 정의에서 테이블 W2에 대한 전방 참조 때문에 오류를 반환합니다.

```
with w1 as (select * from w2), w2 as (select * from w1)
select * from sales;
ERROR:  relation "w2" does not exist
```

WITH 절 하위 쿼리는 SELECT INTO 문으로 구성되지 않을 수 있지만, SELECT INTO 문에 WITH 절을 사용할 수 있습니다.

## 재귀적인 공통 테이블 표현식
<a name="r_WITH_clause-recursive-cte"></a>

재귀 *공통 테이블 표현식(CTE)*은 자신을 참조하는 CTE입니다. 재귀 CTE는 직원과 관리자 간의 보고 관계를 보여주는 조직도와 같은 계층적 데이터를 쿼리하는 데 유용합니다. [예: 재귀 CTE](#r_WITH_clause-recursive-cte-example)을(를) 참조하세요.

또 다른 일반적인 용도는 제품이 여러 구성 요소로 이루어지고 각 구성 요소 자체도 다른 구성 요소 또는 하위 어셈블리로 이루어진 다단계 BOM입니다.

재귀 쿼리의 두 번째 SELECT 하위 쿼리에 WHERE 절을 포함하여 재귀 깊이를 제한해야 합니다. 문제 해결 예는 [예: 재귀 CTE](#r_WITH_clause-recursive-cte-example)을(를) 참조하세요. 그렇지 않으면 다음과 비슷한 오류가 발생할 수 있습니다.
+ `Recursive CTE out of working buffers.`
+ `Exceeded recursive CTE max rows limit, please add correct CTE termination predicates or change the max_recursion_rows parameter.`

**참고**  
`max_recursion_rows`는 무한 재귀 루프를 방지하기 위해 재귀 CTE가 반환할 수 있는 최대 행 수를 설정하는 파라미터입니다. 이 값을 기본값보다 큰 값으로 변경하지 않는 것이 좋습니다. 이렇게 하면 쿼리의 무한 재귀 문제가 클러스터에서 과도한 공간을 차지하는 것을 방지할 수 있습니다.

 재귀 CTE 결과에 대한 정렬 순서 및 제한을 지정할 수 있습니다. 재귀 CTE의 최종 결과에 group by 및 distinct 옵션을 포함할 수 있습니다.

하위 쿼리 내에 WITH RECURSIVE 절을 지정할 수 없습니다. *recursive\$1query* 멤버는 order by 또는 limit 절을 포함할 수 없습니다.

## 예제
<a name="r_WITH_clause-examples"></a>

다음 예에서는 WITH 절을 포함하는 쿼리로서 가능한 가장 간단한 사례를 보여줍니다. VENUECOPY라는 이름의 WITH 쿼리는 VENUE 테이블에서 모든 행을 선택합니다. 다음에는 기본 쿼리가 VENUECOPY에서 모든 행을 선택합니다. VENUECOPY 테이블은 이 쿼리의 지속 시간 동안에만 존재합니다.

```
with venuecopy as (select * from venue)
select * from venuecopy order by 1 limit 10;
```

```
 venueid |         venuename          |    venuecity    | venuestate | venueseats
---------+----------------------------+-----------------+------------+------------
1 | Toyota Park                | Bridgeview      | IL         |          0
2 | Columbus Crew Stadium      | Columbus        | OH         |          0
3 | RFK Stadium                | Washington      | DC         |          0
4 | CommunityAmerica Ballpark  | Kansas City     | KS         |          0
5 | Gillette Stadium           | Foxborough      | MA         |      68756
6 | New York Giants Stadium    | East Rutherford | NJ         |      80242
7 | BMO Field                  | Toronto         | ON         |          0
8 | The Home Depot Center      | Carson          | CA         |          0
9 | Dick's Sporting Goods Park | Commerce City   | CO         |          0
v     10 | Pizza Hut Park             | Frisco          | TX         |          0
(10 rows)
```

다음 예에서는 VENUE\$1SALES와 TOP\$1VENUES라는 두 테이블을 생성하는 WITH 절을 보여줍니다. 두 번째 WITH 절 테이블은 첫 번째 WITH 절 테이블에서 선택합니다. 다음에는, 기본 쿼리 블록의 WHERE 절이 TOP\$1VENUES 테이블을 포함하는 하위 쿼리를 포함합니다.

```
with venue_sales as
(select venuename, venuecity, sum(pricepaid) as venuename_sales
from sales, venue, event
where venue.venueid=event.venueid and event.eventid=sales.eventid
group by venuename, venuecity),

top_venues as
(select venuename
from venue_sales
where venuename_sales > 800000)

select venuename, venuecity, venuestate,
sum(qtysold) as venue_qty,
sum(pricepaid) as venue_sales
from sales, venue, event
where venue.venueid=event.venueid and event.eventid=sales.eventid
and venuename in(select venuename from top_venues)
group by venuename, venuecity, venuestate
order by venuename;
```

```
        venuename       |   venuecity   | venuestate | venue_qty | venue_sales
------------------------+---------------+------------+-----------+-------------
August Wilson Theatre   | New York City | NY         |      3187 |  1032156.00
Biltmore Theatre        | New York City | NY         |      2629 |   828981.00
Charles Playhouse       | Boston        | MA         |      2502 |   857031.00
Ethel Barrymore Theatre | New York City | NY         |      2828 |   891172.00
Eugene O'Neill Theatre  | New York City | NY         |      2488 |   828950.00
Greek Theatre           | Los Angeles   | CA         |      2445 |   838918.00
Helen Hayes Theatre     | New York City | NY         |      2948 |   978765.00
Hilton Theatre          | New York City | NY         |      2999 |   885686.00
Imperial Theatre        | New York City | NY         |      2702 |   877993.00
Lunt-Fontanne Theatre   | New York City | NY         |      3326 |  1115182.00
Majestic Theatre        | New York City | NY         |      2549 |   894275.00
Nederlander Theatre     | New York City | NY         |      2934 |   936312.00
Pasadena Playhouse      | Pasadena      | CA         |      2739 |   820435.00
Winter Garden Theatre   | New York City | NY         |      2838 |   939257.00
(14 rows)
```

다음 두 예에서는 WITH 절 하위 쿼리를 기반으로 테이블 참조의 범위에 대한 규칙을 보여줍니다. 첫 번째 쿼리가 실행되지만 두 번째 쿼리는 예상된 오류가 발생하며 실패합니다. 첫 번째 쿼리는 기본 쿼리의 SELECT 목록 내에 WITH 절 하위 쿼리가 있습니다. WITH 절(HOLIDAYS)에 의해 정의되는 테이블은 SELECT 목록에 있는 하위 쿼리의 FROM 절에 참조됩니다.

```
select caldate, sum(pricepaid) as daysales,
(with holidays as (select * from date where holiday ='t')
select sum(pricepaid)
from sales join holidays on sales.dateid=holidays.dateid
where caldate='2008-12-25') as dec25sales
from sales join date on sales.dateid=date.dateid
where caldate in('2008-12-25','2008-12-31')
group by caldate
order by caldate;

caldate   | daysales | dec25sales
-----------+----------+------------
2008-12-25 | 70402.00 |   70402.00
2008-12-31 | 12678.00 |   70402.00
(2 rows)
```

기본 쿼리뿐 아니라 SELECT 목록 하위 쿼리에서 HOLIDAYS 테이블 참조를 시도하므로 두 번째 쿼리는 실패합니다. 기본 쿼리 참조는 범위를 벗어나는 주제입니다.

```
select caldate, sum(pricepaid) as daysales,
(with holidays as (select * from date where holiday ='t')
select sum(pricepaid)
from sales join holidays on sales.dateid=holidays.dateid
where caldate='2008-12-25') as dec25sales
from sales join holidays on sales.dateid=holidays.dateid
where caldate in('2008-12-25','2008-12-31')
group by caldate
order by caldate;

ERROR:  relation "holidays" does not exist
```

## 예: 재귀 CTE
<a name="r_WITH_clause-recursive-cte-example"></a>

다음은 John에게 직간접적으로 보고하는 직원을 반환하는 재귀 CTE의 예입니다. 재귀 쿼리에는 WHERE 절이 포함되어 있어 재귀 수준을 4단계 미만으로 제한합니다.

```
--create and populate the sample table
  create table employee (
  id int,
  name varchar (20),
  manager_id int
  );
  
  insert into employee(id, name, manager_id)  values
(100, 'Carlos', null),
(101, 'John', 100),
(102, 'Jorge', 101),
(103, 'Kwaku', 101),
(110, 'Liu', 101),
(106, 'Mateo', 102),
(110, 'Nikki', 103),
(104, 'Paulo', 103),
(105, 'Richard', 103),
(120, 'Saanvi', 104),
(200, 'Shirley', 104),
(201, 'Sofía', 102),
(205, 'Zhang', 104);
  
--run the recursive query
  with recursive john_org(id, name, manager_id, level) as
( select id, name, manager_id, 1 as level
  from employee
  where name = 'John'
  union all
  select e.id, e.name, e.manager_id, level + 1 as next_level
  from employee e, john_org j
  where e.manager_id = j.id and level < 4
  )
 select distinct id, name, manager_id from john_org order by manager_id;
```

다음은 쿼리 결과입니다.

```
    id        name      manager_id
  ------+-----------+--------------
   101    John           100
   102    Jorge          101
   103    Kwaku          101
   110    Liu            101
   201    Sofía          102
   106    Mateo          102
   110    Nikki          103
   104    Paulo          103
   105    Richard        103
   120    Saanvi         104
   200    Shirley        104
   205    Zhang          104
```

다음은 John의 부서의 조직도입니다.

![\[John의 부서의 조직도 다이어그램.\]](http://docs.aws.amazon.com/ko_kr/redshift/latest/dg/images/org-chart.png)


# SELECT 목록
<a name="r_SELECT_list"></a>

**Topics**
+ [구문](#r_SELECT_list-synopsis)
+ [파라미터](#r_SELECT_list-parameters)
+ [사용 노트](#r_SELECT_list_usage_notes)
+ [예제](#r_SELECT_list-examples)

SELECT 목록은 쿼리에서 반환하도록 하려는 열, 함수 및 표현식의 이름을 지정합니다. 목록은 쿼리의 출력을 나타냅니다.

SQL 함수에 대한 자세한 내용은 [SQL 함수 참조](c_SQL_functions.md) 섹션을 참조하세요. 표현식에 대한 자세한 내용은 [조건 표현식](c_conditional_expressions.md) 섹션을 참조하세요.

## 구문
<a name="r_SELECT_list-synopsis"></a>

```
SELECT
[ TOP number ]
[ ALL | DISTINCT ] * | expression [ AS column_alias ] [, ...]
```

## 파라미터
<a name="r_SELECT_list-parameters"></a>

TOP *number*   
TOP은 양의 정수를 인수로 취해 클라이언트로 반환되는 행의 수를 한정합니다. TOP 절을 이용한 동작은 LIMIT 절을 이용한 동작과 같습니다. 반환되는 행 수는 고정되지만 행 집합은 그렇지 않습니다. 일관된 행 집합을 반환하려면 ORDER BY 절과 함께 TOP 또는 LIMIT를 사용하십시오.

ALL   
DISTINCT를 지정하지 않을 경우의 기본 동작을 정의하는 중복 키워드입니다. `SELECT ALL *`은 `SELECT *`와 동일한 의미입니다(즉, 모든 열에 대해 모든 행을 선택하고 중복 항목을 유지함).

DISTINCT   
하나 이상의 열에서 일치하는 값을 바탕으로 결과 집합에서 중복된 행을 제거하는 옵션입니다.  
애플리케이션이 잘못된 외래 키 또는 프라이머리 키를 허용하는 경우에는 쿼리가 잘못된 결과를 반환할 수 있습니다. 예를 들어 SELECT DISTINCT 쿼리는 프라이머리 키 열이 고유한 값만을 포함하지 않을 경우 중복 행을 반환할 수도 있습니다. 자세한 내용은 [테이블 제약 조건 정의](https://docs.aws.amazon.com/redshift/latest/dg/t_Defining_constraints.html) 단원을 참조하세요.

\$1(별표)   
테이블의 전체 내용(모든 열과 모든 행)을 반환합니다.

 * expression*   
쿼리에서 참조하는 테이블에 존재하는 하나 이상의 열에서 형성되는 표현식입니다. 표현식은 SQL 함수를 포함할 수 있습니다. 예:   

```
avg(datediff(day, listtime, saletime))
```

AS *column\$1alias*   
최종 결과 집합에 사용될 열의 임시 이름입니다. AS 키워드는 옵션입니다. 예:   

```
avg(datediff(day, listtime, saletime)) as avgwait
```
표현식에 대해 단순한 열 이름이 아닌 별칭을 지정하지 않을 경우 결과 집합은 그 열에 기본 이름을 적용합니다.  
별칭은 대상 목록에 정의되는 즉시 인식됩니다. 동일한 대상 목록에서 별칭 뒤에 정의된 다른 표현식에 별칭을 사용할 수 있습니다. 다음 예는 이를 보여 줍니다.  

```
select clicks / impressions as probability, round(100 * probability, 1) as percentage from raw_data;
```
측방 별칭 참조를 사용하면 동일한 대상 목록에서 더 복잡한 표현식을 작성할 때 별칭 처리된 표현식을 반복할 필요가 없다는 이점이 있습니다. Amazon Redshift에서는 이런 형식의 참조를 구문 분석할 때 이전에 정의된 별칭을 일렬로 정렬합니다. `FROM` 절에 이전에 별칭 처리된 표현식과 동일한 이름을 가진 열이 정의되어 있는 경우 `FROM` 절의 열에 우선 순위가 적용됩니다. 예를 들어 위의 쿼리에서 raw\$1data 테이블에 'probability' 열이 있는 경우 대상 목록의 두 번째 표현식에 있는 'probability'는 별칭 이름 'probability' 대신 이 열을 나타냅니다.

## 사용 노트
<a name="r_SELECT_list_usage_notes"></a>

TOP은 SQL 확장으로, LIMIT 동작에 대한 대안을 제공합니다. 같은 쿼리에 TOP과 LIMIT를 사용할 수 없습니다.

## 예제
<a name="r_SELECT_list-examples"></a>

다음 예에서는 SALES 테이블의 행 10개를 반환합니다. 쿼리는 TOP 절을 사용하지만 ORDER BY 절이 지정되지 않았으므로, 여전히 예측할 수 없는 행 집합을 반환합니다.

```
select top 10 *
from sales;
```

다음 쿼리는 기능적으로는 동일하지만 TOP 절 대신 LIMIT 절을 사용합니다.

```
select *
from sales
limit 10;
```

다음 예에서는 TOP 절을 사용하여 SALES 테이블에서 최초 10개의 행을 반환하며, QTYSOLD 열을 기준으로 내림차순으로 정렬합니다.

```
select top 10 qtysold, sellerid
from sales
order by qtysold desc, sellerid;

qtysold | sellerid
--------+----------
8 |      518
8 |      520
8 |      574
8 |      718
8 |      868
8 |     2663
8 |     3396
8 |     3726
8 |     5250
8 |     6216
(10 rows)
```

다음 예에서는 QTYSOLD 열을 기준으로 정렬된 SALES 테이블에서 최초 2개의 QTYSOLD 및 SELLERID 값을 반환합니다.

```
select top 2 qtysold, sellerid
from sales
order by qtysold desc, sellerid;

qtysold | sellerid
--------+----------
8 |      518
8 |      520
(2 rows)
```

다음 예에서는 CATEGORY 테이블의 개별 범주 그룹 목록을 확인할 수 있습니다.

```
select distinct catgroup from category
order by 1;

catgroup
----------
Concerts
Shows
Sports
(3 rows)

--the same query, run without distinct
select catgroup from category
order by 1;

catgroup
----------
Concerts
Concerts
Concerts
Shows
Shows
Shows
Sports
Sports
Sports
Sports
Sports
(11 rows)
```

다음 예에서는 2008년 12월의 고유한 주 번호 집합을 반환합니다. DISTINCT 절을 사용하지 않으면 문은 행 31개를 반환하거나 해당 월의 날짜별로 행을 하나씩 반환합니다.

```
select distinct week, month, year
from date
where month='DEC' and year=2008
order by 1, 2, 3;

week | month | year
-----+-------+------
49 | DEC   | 2008
50 | DEC   | 2008
51 | DEC   | 2008
52 | DEC   | 2008
53 | DEC   | 2008
(5 rows)
```



# EXCLUDE column\$1list
<a name="r_EXCLUDE_list"></a>

EXCLUDE column\$1list는 쿼리 결과에서 제외되는 열의 이름을 나열합니다. EXCLUDE 옵션을 사용하는 것은 많은 열이 포함된 테이블인 *넓은* 테이블에서 열의 하위 집합만 제외해야 하는 경우에 유용합니다.

**Topics**
+ [구문](#r_EXCLUDE_list-synopsis)
+ [파라미터](#r_EXCLUDE_list-parameters)
+ [예제](#r_EXCLUDE_list-examples)

## 구문
<a name="r_EXCLUDE_list-synopsis"></a>

```
EXCLUDE column_list
```

## 파라미터
<a name="r_EXCLUDE_list-parameters"></a>

 *column\$1list*   
쿼리에서 참조하는 테이블에 있는 하나 이상의 열 이름을 쉼표로 구분한 목록입니다. *column\$1list*는 선택적으로 괄호로 묶을 수 있습니다. 열 이름의 제외 목록에는 열 이름만 지원되며 표현식(예: `upper(col1)`) 또는 별표(\$1)는 지원되지 않습니다.  

```
column-name, ... | ( column-name, ... )
```
예제:   

```
SELECT * EXCLUDE col1, col2 FROM tablea;
```

```
SELECT * EXCLUDE (col1, col2) FROM tablea;
```

## 예제
<a name="r_EXCLUDE_list-examples"></a>

다음 예에서는 salesid, listid, sellerid, buyerid, eventid, dateid, qtysold, pricepaid, commission, saletime 열이 포함된 SALES 테이블을 사용합니다. SALES 테이블에 대한 자세한 내용은 [샘플 데이터베이스](c_sampledb.md) 섹션을 참조하세요.

다음 예에서는 SALES 테이블에서 행을 반환하지만 SALETIME 열은 제외합니다.

```
SELECT * EXCLUDE saletime FROM sales;

salesid | listid  | sellerid | buyerid | eventid | dateid  | qtysold  | pricepaid  | commission
--------+---------+----------+---------+---------+---------+----------+------------+-----------
150314  | 173969  | 48680    | 816     | 8762    | 1827    | 2        | 688        | 103.2	
8325    | 8942    | 23600    | 1078    | 2557    | 1828    | 5        | 525        |  78.75	
46807   | 52711   | 34388    | 1047    | 2046    | 1828    | 2        | 482        |  72.3	
...
```

다음 예에서는 SALES 테이블에서 행을 반환하지만 QTYSOLD 및 SALETIME 열은 제외합니다.

```
SELECT * EXCLUDE (qtysold, saletime) FROM sales;

salesid | listid  | sellerid | buyerid | eventid | dateid  | pricepaid  | commission
--------+---------+----------+---------+---------+---------+------------+-----------
150314  | 173969  | 48680    | 816     | 8762    | 1827    | 688        | 103.2	
8325    | 8942    | 23600    | 1078    | 2557    | 1828    | 525        |  78.75	
46807   | 52711   | 34388    | 1047    | 2046    | 1828    | 482        |  72.3	
...
```

다음 예에서는 SALES 테이블에서 행을 반환하지만 SALETIME 열은 제외하는 보기를 생성합니다.

```
CREATE VIEW sales_view AS SELECT * EXCLUDE saletime FROM sales;
SELECT * FROM sales_view;

salesid | listid  | sellerid | buyerid | eventid | dateid  | qtysold  | pricepaid  | commission
--------+---------+----------+---------+---------+---------+----------+------------+-----------
150314  | 173969  | 48680    | 816     | 8762    | 1827    | 2        | 688        | 103.2	
8325    | 8942    | 23600    | 1078    | 2557    | 1828    | 5        | 525        |  78.75	
46807   | 52711   | 34388    | 1047    | 2046    | 1828    | 2        | 482        |  72.3	
...
```

다음 예에서는 임시 테이블에 제외되지 않는 열만 선택합니다.

```
SELECT * EXCLUDE saletime INTO TEMP temp_sales FROM sales;
SELECT * FROM temp_sales;

salesid | listid  | sellerid | buyerid | eventid | dateid  | qtysold  | pricepaid  | commission
--------+---------+----------+---------+---------+---------+----------+------------+-----------
150314  | 173969  | 48680    | 816     | 8762    | 1827    | 2        | 688        | 103.2	
8325    | 8942    | 23600    | 1078    | 2557    | 1828    | 5        | 525        |  78.75	
46807   | 52711   | 34388    | 1047    | 2046    | 1828    | 2        | 482        |  72.3	
...
```

# FROM 절
<a name="r_FROM_clause30"></a>

쿼리의 FROM 절은 데이터가 선택되는 테이블 참조(테이블, 뷰, 하위 쿼리)를 나열합니다. 여러 개의 테이블 참조가 목록에 표시되는 경우 FROM 절 또는 WHERE 절에서 알맞은 구문을 사용하여 테이블을 조인해야 합니다. 조인 기준이 지정되지 않은 경우 시스템에서는 쿼리를 크로스 조인(데카르트 곱)으로 처리합니다.

**Topics**
+ [구문](#r_FROM_clause30-synopsis)
+ [파라미터](#r_FROM_clause30-parameters)
+ [사용 노트](#r_FROM_clause_usage_notes)
+ [PIVOT 및 UNPIVOT 예](r_FROM_clause-pivot-unpivot-examples.md)
+ [JOIN 예](r_Join_examples.md)
+ [UNNEST 예제](r_FROM_clause-unnest-examples.md)

## 구문
<a name="r_FROM_clause30-synopsis"></a>

```
FROM table_reference [, ...]
```

여기서 *table\$1reference*는 다음 중 하나입니다.

```
with_subquery_table_name [ table_alias ]
table_name [ * ] [ table_alias ]
( subquery ) [ table_alias ]
table_reference [ NATURAL ] join_type table_reference
   [ ON join_condition | USING ( join_column [, ...] ) ]
table_reference  join_type super_expression 
   [ ON join_condition ]
table_reference PIVOT ( 
   aggregate(expr) [ [ AS ] aggregate_alias ]
   FOR column_name IN ( expression [ AS ] in_alias [, ...] )
) [ table_alias ]
table_reference UNPIVOT [ INCLUDE NULLS | EXCLUDE NULLS ] ( 
   value_column_name 
   FOR name_column_name IN ( column_reference [ [ AS ]
   in_alias ] [, ...] )
) [ table_alias ]
UNPIVOT expression AS value_alias [ AT attribute_alias ]
( super_expression.attribute_name ) AS value_alias [ AT index_alias ]
UNNEST ( column_reference )
  [AS] table_alias ( unnested_column_name )
UNNEST ( column_reference ) WITH OFFSET
  [AS] table_alias ( unnested_column_name, [offset_column_name] )
```

선택적 *table\$1alias*를 사용하여 다음과 같이 테이블 및 복합 테이블 참조와 원하는 경우 해당 열에 임시 이름을 지정할 수 있습니다.

```
[ AS ] alias [ ( column_alias [, ...] ) ]
```

## 파라미터
<a name="r_FROM_clause30-parameters"></a>

 *with\$1subquery\$1table\$1name*   
[WITH 절](r_WITH_clause.md)에서 하위 쿼리에 의해 정의되는 테이블입니다.

 *table\$1name*   
테이블 또는 뷰의 이름입니다.

 *별칭*   
테이블 또는 뷰의 임시 대체 이름입니다. 하위 쿼리에서 파생되는 테이블에 대해 별칭을 입력해야 합니다. 다른 테이블 참조에서 별칭은 옵션입니다. AS 키워드는 항상 옵션입니다. 테이블 별칭은 WHERE 절과 같이 쿼리의 다른 부분에 있는 테이블을 편리하게 식별하는 바로 가기의 역할을 합니다. 예:   

```
select * from sales s, listing l
where s.listid=l.listid
```

 *column\$1alias*   
테이블 또는 뷰에 있는 열의 임시 대체 이름입니다.

 *subquery*   
테이블로 평가되는 쿼리 표현식입니다. 테이블은 쿼리의 지속 시간 동안만 존재하며 일반적으로 이름 또는 *별칭*이 주어집니다. 그러나 별칭이 필수는 아닙니다. 하위 쿼리에서 파생되는 테이블의 열 이름을 정의할 수도 있습니다. 하위 쿼리의 결과를 다른 테이블에 조인하고 쿼리의 다른 곳에서 열을 선택하거나 제한하려는 경우 열 별칭의 이름 지정이 중요합니다.  
하위 쿼리는 ORDER BY 절을 포함할 수 있지만, LIMIT 또는 OFFSET 절도 지정하지 않으면 ORDER BY 절이 아무런 효과도 없을 수 있습니다.

NATURAL   
두 테이블에서 조인 열로서 똑같이 명명된 열의 쌍을 전부 자동으로 사용하는 조인을 정의합니다. 명시적 조인 조건은 필요하지 않습니다. 예를 들어, CATEGORY 및 EVENT 테이블에 모두 CATID로 명명된 열이 있는 경우 이러한 테이블의 자연 조인은 CATID 열에 적용되는 조인입니다.  
NATURAL 조인이 지정되어 있지만 조인되는 테이블에 똑같은 이름의 열 쌍이 존재하지 않는 경우 쿼리는 기본적으로 크로스 조인이 됩니다.

 *join\$1type*   
다음과 같은 조인 유형 중 하나를 지정합니다.  
+ [INNER] JOIN 
+ LEFT [OUTER] JOIN 
+ RIGHT [OUTER] JOIN 
+ FULL [OUTER] JOIN 
+ CROSS JOIN 
크로스 조인은 정규화되지 않은 조인으로, 두 테이블의 데카르트 곱을 반환합니다.  
내부 및 외부 조인은 정규화된 조인입니다. 이런 조인은 FROM 절에서 ON 또는 USING 구문으로 암시적으로(자연 조인으로) 정규화되거나 WHERE 절 조건으로 암시적으로 정규화됩니다.  
내부 조인은 조인 조건이나 조인 열의 목록을 기반으로 일치하는 행만 반환합니다. 외부 조인은 동등한 내부 조인이 반환하는 모든 행과 "왼쪽" 테이블, "오른쪽" 테이블 또는 두 테이블 모두에서 일치하지 않는 행을 반환합니다. 왼쪽 테이블은 처음에 목록으로 표시되는 테이블이고, 오른쪽 테이블은 두 번째로 목록으로 표시되는 테이블입니다. 일치하지 않는 행은 출력 열의 간격을 채우기 위해 NULL 값을 포함합니다.

ON *join\$1condition*   
조인 열이 ON 키워드 뒤에 나오는 조건으로 규정되는 조인 사양의 유형입니다. 예:   

```
sales join listing
on sales.listid=listing.listid and sales.eventid=listing.eventid
```

USING ( *join\$1column* [, ...] )   
조인 열이 괄호 안에 묶여 표시되는 조인 사양의 유형입니다. 여러 개의 조인 열이 지정되어 있는 경우 이런 열은 쉼표로 구분됩니다. USING 키워드는 목록에 선행해야 합니다. 예제:   

```
sales join listing
using (listid,eventid)
```

PIVOT  
읽기 쉬운 형식으로 테이블형 데이터를 표시하기 위해 행에서 열로 출력을 회전합니다. 출력은 여러 열에 가로로 표시됩니다. PIVOT은 집계 표현식을 사용하여 출력 형식을 지정하는 집계가 있는 GROUP BY 쿼리와 유사합니다. 그러나 GROUP BY와 달리 결과는 행 대신 열로 반환됩니다.  
PIVOT 및 UNPIVOT을 사용하여 쿼리하는 방법을 보여주는 예는 [PIVOT 및 UNPIVOT 예](r_FROM_clause-pivot-unpivot-examples.md) 섹션을 참조하세요.

UNPIVOT  
*UNPIVOT을 사용하여 열을 행으로 교체* - 이 연산자는 입력 테이블 또는 쿼리 결과의 결과 열을 행으로 변환하여 출력을 더 읽기 쉽게 만듭니다. UNPIVOT은 입력 열의 데이터를 이름 열과 값 열의 두 결과 열로 결합합니다. 이름 열에는 입력의 열 이름이 행 항목으로 포함됩니다. 값 열에는 집계 결과와 같은 입력 열의 값이 포함됩니다. 예를 들어 다양한 카테고리의 항목 수입니다.  
*UNPIVOT(SUPER)을 사용한 객체 피벗 해제* - 객체 피벗을 해제할 수 있습니다. 여기서 *표현식*은 다른 FROM 절 항목을 참조하는 SUPER 표현식입니다. 자세한 내용은 [객체 피벗 해제](query-super.md#unpivoting) 섹션을 참조하세요. JSON 형식 데이터와 같은 반정형 데이터를 쿼리하는 방법을 보여주는 예도 있습니다.

*super\$1expression*  
유효한 SUPER 표현식입니다. Amazon Redshift는 지정된 속성의 각 값에 대해 하나의 행을 반환합니다. SUPER 데이터 유형에 대한 자세한 내용은 [SUPER 형식](r_SUPER_type.md) 섹션을 참조하세요. 중첩 해제되는 SUPER 값에 대한 자세한 내용은 [쿼리 중첩 해제](query-super.md#unnest) 섹션을 참조하세요.

*attribute\$1name*  
SUPER 표현식에 있는 속성의 이름입니다.

*index\$1alias*  
SUPER 표현식에서 값의 위치를 나타내는 인덱스의 별칭입니다.

UNNEST  
일반적으로 SUPER 배열인 중첩 구조를 중첩되지 않은 요소가 포함된 열로 확장합니다. SUPER 데이터 중첩 해제에 대한 자세한 내용은 [반정형 데이터 쿼리](query-super.md) 섹션을 참조하세요. 예시는 [UNNEST 예제](r_FROM_clause-unnest-examples.md) 섹션을 참조하세요.

*unnested\$1column\$1name*  
중첩되지 않은 요소가 포함된 열의 이름입니다.

UNNEST ... WITH OFFSET  
중첩되지 않은 출력에 오프셋 열을 추가합니다. 여기서 오프셋은 배열에 있는 각 요소의 0부터 시작하는 인덱스를 나타냅니다. 이 변형은 배열 내 요소의 위치를 확인하려는 경우에 유용합니다. SUPER 데이터 중첩 해제에 대한 자세한 내용은 [반정형 데이터 쿼리](query-super.md) 섹션을 참조하세요. 예시는 [UNNEST 예제](r_FROM_clause-unnest-examples.md) 섹션을 참조하세요.

*offset\$1column\$1name*  
인덱스 열이 출력에 표시되는 방식을 명시적으로 정의할 수 있는 오프셋 열의 사용자 지정 이름입니다. 이 파라미터는 선택 사항입니다. 기본적으로 오프셋 열 이름은 `offset_col`입니다.

## 사용 노트
<a name="r_FROM_clause_usage_notes"></a>

조인 열은 비교 가능한 데이터 형식이 있어야 합니다.

NATURAL 또는 USING 조인은 중간 결과 집합에 조인 열의 각 쌍 중 하나만 유지합니다.

ON 구문이 있는 조인은 중간 결과 집합에 두 조인 열을 모두 유지합니다.

또한 [WITH 절](r_WITH_clause.md) 섹션도 참조하세요.

# PIVOT 및 UNPIVOT 예
<a name="r_FROM_clause-pivot-unpivot-examples"></a>

PIVOT 및 UNPIVOT은 각각 쿼리 출력을 행에서 열로, 열에서 행으로 회전하는 FROM 절의 파라미터입니다. 테이블 쿼리 결과를 읽기 쉬운 형식으로 나타냅니다. 다음 예제에서는 테스트 데이터와 쿼리를 사용하여 사용 방법을 보여줍니다.

이러한 파라미터 및 기타 파라미터에 대한 자세한 내용은 [FROM 절](https://docs.aws.amazon.com/redshift/latest/dg/r_FROM_clause30.html) 단원을 참조하세요.

## PIVOT 예
<a name="r_FROM_clause-pivot-examples"></a>

샘플 테이블과 데이터를 설정하고 이를 사용하여 후속 예제 쿼리를 실행합니다.

```
CREATE TABLE part (
    partname varchar,
    manufacturer varchar,
    quality int,
    price decimal(12, 2)
);

INSERT INTO part VALUES ('prop', 'local parts co', 2, 10.00);
INSERT INTO part VALUES ('prop', 'big parts co', NULL, 9.00);
INSERT INTO part VALUES ('prop', 'small parts co', 1, 12.00);

INSERT INTO part VALUES ('rudder', 'local parts co', 1, 2.50);
INSERT INTO part VALUES ('rudder', 'big parts co', 2, 3.75);
INSERT INTO part VALUES ('rudder', 'small parts co', NULL, 1.90);

INSERT INTO part VALUES ('wing', 'local parts co', NULL, 7.50);
INSERT INTO part VALUES ('wing', 'big parts co', 1, 15.20);
INSERT INTO part VALUES ('wing', 'small parts co', NULL, 11.80);
```

`price`에 대한 `AVG` 집계가 있는 `partname`에 대한 PIVOT.

```
SELECT *
FROM (SELECT partname, price FROM part) PIVOT (
    AVG(price) FOR partname IN ('prop', 'rudder', 'wing')
);
```

쿼리 결과는 다음과 같이 출력됩니다.

```
  prop   |  rudder  |  wing
---------+----------+---------
 10.33   | 2.71     | 11.50
```

이전 예에서 결과는 열로 변환됩니다. 다음 예는 평균 가격을 열이 아닌 행으로 반환하는 `GROUP BY` 쿼리를 보여줍니다.

```
SELECT partname, avg(price)
FROM (SELECT partname, price FROM part)
WHERE partname IN ('prop', 'rudder', 'wing')
GROUP BY partname;
```

쿼리 결과는 다음과 같이 출력됩니다.

```
 partname |  avg
----------+-------
 prop     | 10.33
 rudder   |  2.71
 wing     | 11.50
```

암시적 열로 `manufacturer`가 있는 `PIVOT` 예.

```
SELECT *
FROM (SELECT quality, manufacturer FROM part) PIVOT (
    count(*) FOR quality IN (1, 2, NULL)
);
```

쿼리 결과는 다음과 같이 출력됩니다.

```
 manufacturer      | 1  | 2  | null
-------------------+----+----+------
 local parts co    | 1  | 1  |  1
 big parts co      | 1  | 1  |  1
 small parts co    | 1  | 0  |  2
```

 `PIVOT` 정의에서 참조되지 않는 입력 테이블 열은 암시적으로 결과 테이블에 추가됩니다. 이는 앞의 예에서 `manufacturer` 열의 경우입니다. 이 예는 또한 `NULL`이 `IN` 연산자에 유효한 값임을 보여줍니다.

`PIVOT`위의 예에서 은 가 포함된 다음 쿼리와 유사한 정보를 반환합니다.`GROUP BY` 차이점은 `PIVOT`이 열 `2`와 제조업체 `small parts co`에 대해 값 `0`을 반환한다는 것입니다. `GROUP BY` 쿼리에는 해당 행이 없습니다. 대부분의 경우 행에 지정된 열에 대한 입력 데이터가 없으면 `PIVOT`은 `NULL`을 삽입합니다. 그러나 count 집계는 `NULL`을 반환하지 않고 `0`이 기본값입니다.

```
SELECT manufacturer, quality, count(*)
FROM (SELECT quality, manufacturer FROM part)
WHERE quality IN (1, 2) OR quality IS NULL
GROUP BY manufacturer, quality
ORDER BY manufacturer;
```

쿼리 결과는 다음과 같이 출력됩니다.

```
 manufacturer        | quality | count
---------------------+---------+-------
 big parts co        |         |     1
 big parts co        |       2 |     1
 big parts co        |       1 |     1
 local parts co      |       2 |     1
 local parts co      |       1 |     1
 local parts co      |         |     1
 small parts co      |       1 |     1
 small parts co      |         |     2
```

 PIVOT 연산자는 집계 표현식과 `IN` 연산자의 각 값에 대한 선택적 별칭을 허용합니다. 별칭을 사용하여 열 이름을 사용자 지정합니다. 집계 별칭이 없는 경우 `IN` 목록 별칭이 사용됩니다. 그렇지 않으면 이름을 구분하기 위해 집계 별칭이 밑줄과 함께 열 이름에 추가됩니다.

```
SELECT *
FROM (SELECT quality, manufacturer FROM part) PIVOT (
    count(*) AS count FOR quality IN (1 AS high, 2 AS low, NULL AS na)
);
```

쿼리 결과는 다음과 같이 출력됩니다.

```
 manufacturer      | high_count  | low_count | na_count
-------------------+-------------+-----------+----------
 local parts co    |           1 |         1 |        1
 big parts co      |           1 |         1 |        1
 small parts co    |           1 |         0 |        2
```

다음 샘플 테이블과 데이터를 설정하고 이를 사용하여 후속 예제 쿼리를 실행합니다. 데이터는 여러 호텔의 예약 날짜를 나타냅니다.

```
CREATE TABLE bookings (
    booking_id int,
    hotel_code char(8),
    booking_date date,
    price decimal(12, 2)
);

INSERT INTO bookings VALUES (1, 'FOREST_L', '02/01/2023', 75.12);
INSERT INTO bookings VALUES (2, 'FOREST_L', '02/02/2023', 75.00);
INSERT INTO bookings VALUES (3, 'FOREST_L', '02/04/2023', 85.54);

INSERT INTO bookings VALUES (4, 'FOREST_L', '02/08/2023', 75.00);
INSERT INTO bookings VALUES (5, 'FOREST_L', '02/11/2023', 75.00);
INSERT INTO bookings VALUES (6, 'FOREST_L', '02/14/2023', 90.00);

INSERT INTO bookings VALUES (7, 'FOREST_L', '02/21/2023', 60.00);
INSERT INTO bookings VALUES (8, 'FOREST_L', '02/22/2023', 85.00);
INSERT INTO bookings VALUES (9, 'FOREST_L', '02/27/2023', 90.00);

INSERT INTO bookings VALUES (10, 'DESERT_S', '02/01/2023', 98.00);
INSERT INTO bookings VALUES (11, 'DESERT_S', '02/02/2023', 75.00);
INSERT INTO bookings VALUES (12, 'DESERT_S', '02/04/2023', 85.00);

INSERT INTO bookings VALUES (13, 'DESERT_S', '02/05/2023', 75.00);
INSERT INTO bookings VALUES (14, 'DESERT_S', '02/06/2023', 34.00);
INSERT INTO bookings VALUES (15, 'DESERT_S', '02/09/2023', 85.00);

INSERT INTO bookings VALUES (16, 'DESERT_S', '02/12/2023', 23.00);
INSERT INTO bookings VALUES (17, 'DESERT_S', '02/13/2023', 76.00);
INSERT INTO bookings VALUES (18, 'DESERT_S', '02/14/2023', 85.00);

INSERT INTO bookings VALUES (19, 'OCEAN_WV', '02/01/2023', 98.00);
INSERT INTO bookings VALUES (20, 'OCEAN_WV', '02/02/2023', 75.00);
INSERT INTO bookings VALUES (21, 'OCEAN_WV', '02/04/2023', 85.00);

INSERT INTO bookings VALUES (22, 'OCEAN_WV', '02/06/2023', 75.00);
INSERT INTO bookings VALUES (23, 'OCEAN_WV', '02/09/2023', 34.00);
INSERT INTO bookings VALUES (24, 'OCEAN_WV', '02/12/2023', 85.00);

INSERT INTO bookings VALUES (25, 'OCEAN_WV', '02/13/2023', 23.00);
INSERT INTO bookings VALUES (26, 'OCEAN_WV', '02/14/2023', 76.00);
INSERT INTO bookings VALUES (27, 'OCEAN_WV', '02/16/2023', 85.00);

INSERT INTO bookings VALUES (28, 'CITY_BLD', '02/01/2023', 98.00);
INSERT INTO bookings VALUES (29, 'CITY_BLD', '02/02/2023', 75.00);
INSERT INTO bookings VALUES (30, 'CITY_BLD', '02/04/2023', 85.00);

INSERT INTO bookings VALUES (31, 'CITY_BLD', '02/12/2023', 75.00);
INSERT INTO bookings VALUES (32, 'CITY_BLD', '02/13/2023', 34.00);
INSERT INTO bookings VALUES (33, 'CITY_BLD', '02/17/2023', 85.00);

INSERT INTO bookings VALUES (34, 'CITY_BLD', '02/22/2023', 23.00);
INSERT INTO bookings VALUES (35, 'CITY_BLD', '02/23/2023', 76.00);
INSERT INTO bookings VALUES (36, 'CITY_BLD', '02/24/2023', 85.00);
```

 이 샘플 쿼리에서는 예약 기록을 집계하여 각 주의 합계를 산출합니다. 각 주의 종료일은 열 이름이 됩니다.

```
SELECT * FROM
    (SELECT
       booking_id,
       (date_trunc('week', booking_date::date) + '5 days'::interval)::date as enddate,
       hotel_code AS "hotel code"
FROM bookings
) PIVOT (
    count(booking_id) FOR enddate IN ('2023-02-04','2023-02-11','2023-02-18') 
);
```

쿼리 결과는 다음과 같이 출력됩니다.

```
 hotel code | 2023-02-04  | 2023-02-11 | 2023-02-18
------------+-------------+------------+----------
 FOREST_L   |           3 |          2 |        1
 DESERT_S   |           4 |          3 |        2
 OCEAN_WV   |           3 |          3 |        3
 CITY_BLD   |           3 |          1 |        2
```

 Amazon Redshift는 여러 열에서 피벗하기 위한 CROSSTAB을 지원하지 않습니다. 그러나 다음과 같은 쿼리를 사용하여 PIVOT을 사용한 집계와 유사한 방식으로 행 데이터를 열로 변경할 수 있습니다. 이전 예와 동일한 예약 샘플 데이터를 사용합니다.

```
SELECT 
  booking_date,
  MAX(CASE WHEN hotel_code = 'FOREST_L' THEN 'forest is booked' ELSE '' END) AS FOREST_L,
  MAX(CASE WHEN hotel_code = 'DESERT_S' THEN 'desert is booked' ELSE '' END) AS DESERT_S,
  MAX(CASE WHEN hotel_code = 'OCEAN_WV' THEN 'ocean is booked' ELSE '' END)  AS OCEAN_WV
FROM bookings
GROUP BY booking_date
ORDER BY booking_date asc;
```

샘플 쿼리를 실행하면 예약된 호텔을 나타내는 짧은 문구 옆에 예약 날짜가 표시됩니다.

```
 booking_date  | forest_l         | desert_s         | ocean_wv
---------------+------------------+------------------+--------------------
 2023-02-01    | forest is booked | desert is booked |  ocean is booked
 2023-02-02    | forest is booked | desert is booked |  ocean is booked
 2023-02-04    | forest is booked | desert is booked |  ocean is booked
 2023-02-05    |                  | desert is booked |        
 2023-02-06    |                  | desert is booked |
```

다음은 `PIVOT`에 대한 사용 참고 사항입니다.
+ `PIVOT`은 테이블, 하위 쿼리 및 공통 테이블 표현식(CTE)에 적용할 수 있습니다. `JOIN` 표현식, 재귀 CTE, `PIVOT` 또는 `UNPIVOT` 표현식에는 `PIVOT`을 적용할 수 없습니다. 또한 `SUPER` 비중척 표현식과 Redshift Spectrum 중첩 테이블은 지원되지 않습니다.
+  `PIVOT`에서는 `COUNT`, `SUM`, `MIN`, `MAX` 및 `AVG` 집계 함수를 지원합니다.
+ `PIVOT` 집계 표현식은 지원되는 집계 함수의 호출이어야 합니다. 집계 위의 복잡한 표현식은 지원되지 않습니다. 집계 인수는 `PIVOT` 입력 테이블 이외의 테이블에 대한 참조를 포함할 수 없습니다. 상위 쿼리에 대한 상관 관계가 있는 참조도 지원되지 않습니다. 집계 인수에는 하위 쿼리가 포함될 수 있습니다. 이들은 내부적으로 또는 `PIVOT` 입력 테이블에서 상관될 수 있습니다.
+  `PIVOT IN` 목록 값은 열 참조 또는 하위 쿼리일 수 없습니다. 각 값은 `FOR` 열 참조와 호환되는 유형이어야 합니다.
+  `IN` 목록 값에 별칭이 없으면 `PIVOT`은 기본 열 이름을 생성합니다. 'abc' 또는 5와 같은 상수 `IN` 값의 경우 기본 열 이름은 상수 자체입니다. 복잡한 표현식의 경우 열 이름은 `?column?`와 같은 표준 Amazon Redshift 기본 이름입니다.

## UNPIVOT 예
<a name="r_FROM_clause-unpivot-examples"></a>

샘플 데이터를 설정하고 이를 사용하여 후속 예제를 실행합니다.

```
CREATE TABLE count_by_color (quality varchar, red int, green int, blue int);

INSERT INTO count_by_color VALUES ('high', 15, 20, 7);
INSERT INTO count_by_color VALUES ('normal', 35, NULL, 40);
INSERT INTO count_by_color VALUES ('low', 10, 23, NULL);
```

`UNPIVOT`빨간색, 녹색 및 파란색 입력 열의 .

```
SELECT *
FROM (SELECT red, green, blue FROM count_by_color) UNPIVOT (
    cnt FOR color IN (red, green, blue)
);
```

쿼리 결과는 다음과 같이 출력됩니다.

```
 color | cnt
-------+-----
 red   |  15
 red   |  35
 red   |  10
 green |  20
 green |  23
 blue  |   7
 blue  |  40
```

기본적으로 입력 열의 `NULL` 값은 건너뛰고 결과 행을 생성하지 않습니다.

다음은 `INCLUDE NULLS`가 있는 `UNPIVOT`의 예입니다.

```
SELECT *
FROM (
    SELECT red, green, blue
    FROM count_by_color
) UNPIVOT INCLUDE NULLS (
    cnt FOR color IN (red, green, blue)
);
```

결과 출력값은 다음과 같습니다.

```
 color | cnt
-------+-----
 red   |  15
 red   |  35
 red   |  10
 green |  20
 green |
 green |  23
 blue  |   7
 blue  |  40
 blue  |
```

`INCLUDING NULLS` 파라미터가 설정되면 `NULL` 입력 값이 결과 행을 생성합니다.

암시적 열로 `quality`가 있는 `The following query shows UNPIVOT`.

```
SELECT *
FROM count_by_color UNPIVOT (
    cnt FOR color IN (red, green, blue)
);
```

쿼리 결과는 다음과 같이 출력됩니다.

```
 quality | color | cnt
---------+-------+-----
 high    | red   |  15
 normal  | red   |  35
 low     | red   |  10
 high    | green |  20
 low     | green |  23
 high    | blue  |   7
 normal  | blue  |  40
```

`UNPIVOT` 정의에서 참조되지 않는 입력 테이블의 열은 암시적으로 결과 테이블에 추가됩니다. 이 예에서는 `quality` 열의 경우입니다.

다음 예는 `IN` 목록의 값에 대한 별칭이 있는 `UNPIVOT`을 보여줍니다.

```
SELECT *
FROM count_by_color UNPIVOT (
    cnt FOR color IN (red AS r, green AS g, blue AS b)
);
```

이전 쿼리 결과는 다음과 같이 출력됩니다.

```
 quality | color | cnt
---------+-------+-----
 high    | r     |  15
 normal  | r     |  35
 low     | r     |  10
 high    | g     |  20
 low     | g     |  23
 high    | b     |   7
 normal  | b     |  40
```

`UNPIVOT` 연산자는 각 `IN` 목록 값에서 선택적 별칭을 허용합니다. 각 별칭을 통해 각 `value` 열의 데이터를 사용자 지정할 수 있습니다.

다음은 `UNPIVOT`에 대한 사용 참고 사항입니다.
+ `UNPIVOT`은 테이블, 하위 쿼리 및 공통 테이블 표현식(CTE)에 적용할 수 있습니다. `JOIN` 표현식, 재귀 CTE, `UNPIVOT` 또는 `UNPIVOT` 표현식에는 `PIVOT`을 적용할 수 없습니다. 또한 `SUPER` 비중척 표현식과 Redshift Spectrum 중첩 테이블은 지원되지 않습니다.
+ `UNPIVOT IN` 목록에는 입력 테이블 열 참조만 포함되어야 합니다. `IN` 목록 열에는 모두 호환되는 공통 유형이 있어야 합니다. `UNPIVOT` 값 열에는 이러한 공통 유형이 있습니다. `UNPIVOT` 이름 열은 `VARCHAR`유형입니다.
+ `IN` 목록 값에 별칭이 없으면 `UNPIVOT`은 열 이름을 기본값으로 사용합니다.

# JOIN 예
<a name="r_Join_examples"></a>

SQL JOIN 절은 공통 필드를 기반으로 두 개 이상의 테이블에서 데이터를 결합하는 데 사용됩니다. 지정된 조인 메서드에 따라 결과가 변경될 수도 있고 변경되지 않을 수도 있습니다. JOIN 절의 구문에 대한 자세한 내용은 [파라미터](r_FROM_clause30.md#r_FROM_clause30-parameters) 섹션을 참조하세요.

다음 예에서는 `TICKIT` 샘플 데이터의 데이터를 사용합니다. 데이터베이스 스키마에 대한 자세한 내용은 [샘플 데이터베이스](c_sampledb.md) 섹션을 참조하세요. 샘플 데이터를 로드하는 방법을 알아보려면 Amazon Redshift 시작 안내서**의 [데이터 로드](https://docs.aws.amazon.com/redshift/latest/gsg/rs-gsg-create-sample-db.html) 단원을 참조하세요.

다음 쿼리는 LISTING 테이블과 SALES 테이블 간의 내부 조인(JOIN 키워드 사용 안 함)이며, 여기서 LISTING 테이블의 LISTID는 1에서 5 사이입니다. 이 쿼리는 LISTING 테이블(왼쪽 테이블) 및 SALES 테이블(오른쪽 테이블)에 있는 LISTID 열 값과 일치합니다. 결과는 LISTID 1, 4, 5가 조건과 일치한다는 것을 보여줍니다.

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing, sales
where listing.listid = sales.listid
and listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

다음 쿼리는 왼쪽 외부 조인입니다. 왼쪽 및 오른쪽 외부 조인은 다른 테이블에서 일치 항목이 발견되지 않을 때 조인된 테이블 중 하나에서 값을 유지합니다. 왼쪽 및 오른쪽 테이블은 구문에 나열되는 첫 번째 및 두 번째 테이블입니다. NULL 값은 결과 집합의 "간격"을 채우는 데 사용됩니다. 이 쿼리는 LISTING 테이블(왼쪽 테이블) 및 SALES 테이블(오른쪽 테이블)에 있는 LISTID 열 값과 일치합니다. 결과는 LISTID 2 및 3이 어떤 판매로도 이어지지 않았음을 보여줍니다.

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing left outer join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     2 | NULL   | NULL
     3 | NULL   | NULL
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

다음 쿼리는 오른쪽 외부 조인입니다. 이 쿼리는 LISTING 테이블(왼쪽 테이블) 및 SALES 테이블(오른쪽 테이블)에 있는 LISTID 열 값과 일치합니다. 결과는 LISTID 1, 4, 5가 조건과 일치한다는 것을 보여줍니다.

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing right outer join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

다음 쿼리는 전체 조인입니다. 전체 조인은 다른 테이블에서 일치 항목이 발견되지 않을 때 조인된 테이블의 값을 유지합니다. 왼쪽 및 오른쪽 테이블은 구문에 나열되는 첫 번째 및 두 번째 테이블입니다. NULL 값은 결과 집합의 "간격"을 채우는 데 사용됩니다. 이 쿼리는 LISTING 테이블(왼쪽 테이블) 및 SALES 테이블(오른쪽 테이블)에 있는 LISTID 열 값과 일치합니다. 결과는 LISTID 2 및 3이 어떤 판매로도 이어지지 않았음을 보여줍니다.

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing full join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     2 | NULL   | NULL
     3 | NULL   | NULL
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

다음 쿼리는 전체 조인입니다. 이 쿼리는 LISTING 테이블(왼쪽 테이블) 및 SALES 테이블(오른쪽 테이블)에 있는 LISTID 열 값과 일치합니다. 판매로 이어지지 않는 행(LISTID 2 및 3)만 결과에 있습니다.

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing full join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
and (listing.listid IS NULL or sales.listid IS NULL)
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     2 | NULL   | NULL
     3 | NULL   | NULL
```

다음 예는 ON 절과의 내부 조인입니다. 이 경우 NULL 행은 반환되지 않습니다.

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from sales join listing
on sales.listid=listing.listid and sales.eventid=listing.eventid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

다음 쿼리는 결과를 제한하는 술어가 있는, LISTING 테이블과 SALES 테이블의 교차 조인 또는 데카르트 조인입니다. 이 쿼리는 SALES 테이블과 LISTING 테이블의 LISTID(두 테이블 모두 LISTID 1, 2, 3, 4, 5) 열 값과 일치합니다. 결과는 20개의 행이 조건과 일치한다는 것을 보여줍니다.

```
select sales.listid as sales_listid, listing.listid as listing_listid
from sales cross join listing
where sales.listid between 1 and 5
and listing.listid between 1 and 5
order by 1,2;

sales_listid | listing_listid
-------------+---------------
1            | 1
1            | 2
1            | 3
1            | 4
1            | 5
4            | 1
4            | 2
4            | 3
4            | 4
4            | 5
5            | 1
5            | 1
5            | 2
5            | 2
5            | 3
5            | 3
5            | 4
5            | 4
5            | 5
5            | 5
```

다음 예는 두 테이블 간의 자연 조인입니다. 이 경우 listid, sellerid, eventid, dateid 열은 두 테이블 모두에서 동일한 이름과 데이터 형식을 가지므로 조인 열로 사용됩니다. 결과는 5개 행으로 제한됩니다.

```
select listid, sellerid, eventid, dateid, numtickets
from listing natural join sales
order by 1
limit 5;

listid | sellerid  | eventid | dateid | numtickets
-------+-----------+---------+--------+-----------
113    | 29704     | 4699    | 2075   | 22
115    | 39115     | 3513    | 2062   | 14
116    | 43314     | 8675    | 1910   | 28
118    | 6079      | 1611    | 1862   | 9
163    | 24880     | 8253    | 1888   | 14
```

다음 예는 USING 절을 사용한 두 테이블 간의 조인입니다. 이 경우 listid 및 eventid 열이 조인 열로 사용됩니다. 결과는 5개 행으로 제한됩니다.

```
select listid, listing.sellerid, eventid, listing.dateid, numtickets
from listing join sales
using (listid, eventid)
order by 1
limit 5;

listid | sellerid | eventid | dateid | numtickets
-------+----------+---------+--------+-----------
1      | 36861    | 7872    | 1850   | 10
4      | 8117     | 4337    | 1970   | 8
5      | 1616     | 8647    | 1963   | 4
5      | 1616     | 8647    | 1963   | 4
6      | 47402    | 8240    | 2053   | 18
```

다음 쿼리는 FROM 절에 있는 두 하위 쿼리의 내부 조인입니다. 다음 쿼리는 다양한 범주의 이벤트(콘서트 및 쇼)에 대해 판매된 티켓과 판매되지 않은 티켓의 수를 찾습니다. 이러한 FROM 절 하위 쿼리는 *table* 하위 쿼리로서, 여러 개의 열과 행을 반환할 수 있습니다.

```
select catgroup1, sold, unsold
from
(select catgroup, sum(qtysold) as sold
from category c, event e, sales s
where c.catid = e.catid and e.eventid = s.eventid
group by catgroup) as a(catgroup1, sold)
join
(select catgroup, sum(numtickets)-sum(qtysold) as unsold
from category c, event e, sales s, listing l
where c.catid = e.catid and e.eventid = s.eventid
and s.listid = l.listid
group by catgroup) as b(catgroup2, unsold)

on a.catgroup1 = b.catgroup2
order by 1;

catgroup1 |  sold  | unsold
----------+--------+--------
Concerts  | 195444 |1067199
Shows     | 149905 | 817736
```

# UNNEST 예제
<a name="r_FROM_clause-unnest-examples"></a>

UNNEST는 중첩된 데이터를 데이터의 중첩되지 않은 요소를 포함하는 열로 확장하는 FROM 절의 파라미터입니다. 데이터 중첩 해제에 대한 자세한 내용은 [반정형 데이터 쿼리](query-super.md) 섹션을 참조하세요.

다음 문은 제품 ID 배열이 포함된 `products` 열이 있는 `orders` 테이블을 생성하고 채웁니다. 이 섹션의 예에서는 이 테이블의 샘플 데이터를 사용합니다.

```
CREATE TABLE orders (
    order_id INT,
    products SUPER
);

-- Populate table
INSERT INTO orders VALUES
(1001, JSON_PARSE('[
        {
            "product_id": "P456",
            "name": "Monitor",
            "price": 299.99,
            "quantity": 1,
            "specs": {
                "size": "27 inch",
                "resolution": "4K"
            }
        }
    ]
')),
(1002, JSON_PARSE('
    [
        {
            "product_id": "P567",
            "name": "USB Cable",
            "price": 9.99,
            "quantity": 3
        },
        {
            "product_id": "P678",
            "name": "Headphones",
            "price": 159.99,
            "quantity": 1,
            "specs": {
                "type": "Wireless",
                "battery_life": "20 hours"
            }
        }
    ]
'));
```

다음은 PartiQL 구문을 사용하여 샘플 데이터로 쿼리를 중첩 해제하는 몇 가지 예입니다.

## OFFSET 열을 사용하지 않고 배열 중첩 해제
<a name="r_FROM_clause-unnest-examples-no-offset"></a>

다음 쿼리는 제품 열에서 SUPER 배열을 중첩 해제하며, 각 행은 `order_id` 주문의 항목을 나타냅니다.

```
SELECT o.order_id, unnested_products.product
FROM orders o, UNNEST(o.products) AS unnested_products(product);

 order_id |                                                           product                                                           
----------+-----------------------------------------------------------------------------------------------------------------------------
     1001 | {"product_id":"P456","name":"Monitor","price":299.99,"quantity":1,"specs":{"size":"27 inch","resolution":"4K"}}
     1002 | {"product_id":"P567","name":"USB Cable","price":9.99,"quantity":3}
     1002 | {"product_id":"P678","name":"Headphones","price":159.99,"quantity":1,"specs":{"type":"Wireless","battery_life":"20 hours"}}
(3 rows)
```

다음 쿼리는 각 주문에서 가장 비싼 제품을 찾습니다.

```
SELECT o.order_id, MAX(unnested_products.product)
FROM orders o, UNNEST(o.products) AS unnested_products(product);

 order_id |                                                           product                                                           
----------+-----------------------------------------------------------------------------------------------------------------------------
     1001 | {"product_id":"P456","name":"Monitor","price":299.99,"quantity":1,"specs":{"size":"27 inch","resolution":"4K"}}
     1002 | {"product_id":"P678","name":"Headphones","price":159.99,"quantity":1,"specs":{"type":"Wireless","battery_life":"20 hours"}}
(2 rows)
```

## 암시적 OFFSET 열을 사용하여 배열 중첩 해제
<a name="r_FROM_clause-unnest-examples-implicit-offset"></a>

다음 쿼리는 `UNNEST ... WITH OFFSET` 파라미터를 사용하여 주문 배열 내 각 제품의 0부터 시작하는 위치를 표시합니다.

```
SELECT o.order_id, up.product, up.offset_col
FROM orders o, UNNEST(o.products) WITH OFFSET AS up(product);

 order_id |                                                           product                                                           | offset_col 
----------+-----------------------------------------------------------------------------------------------------------------------------+------------
     1001 | {"product_id":"P456","name":"Monitor","price":299.99,"quantity":1,"specs":{"size":"27 inch","resolution":"4K"}}             |          0
     1002 | {"product_id":"P567","name":"USB Cable","price":9.99,"quantity":3}                                                          |          0
     1002 | {"product_id":"P678","name":"Headphones","price":159.99,"quantity":1,"specs":{"type":"Wireless","battery_life":"20 hours"}} |          1
(3 rows)
```

이 문은 오프셋 열에 대한 별칭을 지정하지 않으므로 Amazon Redshift는 기본적으로 `offset_col`이라는 이름을 지정합니다.

## 명시적 OFFSET 열을 사용하여 배열 중첩 해제
<a name="r_FROM_clause-unnest-examples-explicit-offset"></a>

다음 쿼리는 `UNNEST ... WITH OFFSET` 파라미터를 사용하여 주문 배열 내의 제품을 표시합니다. 이전 예제의 쿼리와 비교하여 이 쿼리의 차이점은 오프셋 열의 이름을 별칭 `idx`로 명시적으로 지정한다는 것입니다.

```
SELECT o.order_id, up.product, up.idx
FROM orders o, UNNEST(o.products) WITH OFFSET AS up(product, idx);

 order_id |                                                           product                                                           | idx 
----------+-----------------------------------------------------------------------------------------------------------------------------+-----
     1001 | {"product_id":"P456","name":"Monitor","price":299.99,"quantity":1,"specs":{"size":"27 inch","resolution":"4K"}}             |   0
     1002 | {"product_id":"P567","name":"USB Cable","price":9.99,"quantity":3}                                                          |   0
     1002 | {"product_id":"P678","name":"Headphones","price":159.99,"quantity":1,"specs":{"type":"Wireless","battery_life":"20 hours"}} |   1
(3 rows)
```

# WHERE 절
<a name="r_WHERE_clause"></a>

WHERE 절은 테이블을 조인하거나 테이블의 열에 조건자를 적용하는 조건을 포함합니다. WHERE 절 또는 FROM 절에서 알맞은 구문을 사용하여 테이블을 내부 조인할 수 있습니다. FROM 절에는 외부 조인 기준을 지정해야 합니다.

## 구문
<a name="r_WHERE_clause-synopsis"></a>

```
[ WHERE condition ]
```

## *조건*
<a name="r_WHERE_clause-synopsis-condition"></a>

테이블 열에서 조인 조건 또는 조건자 같이, 부울 결과를 포함한 임의의 검색 조건입니다. 다음 예는 유효한 조인 조건입니다.

```
sales.listid=listing.listid
sales.listid<>listing.listid
```

다음 예는 테이블의 열에 유효한 조건입니다.

```
catgroup like 'S%'
venueseats between 20000 and 50000
eventname in('Jersey Boys','Spamalot')
year=2008
length(catdesc)>25
date_part(month, caldate)=6
```

조건은 단순하거나 복잡할 수 있는데, 복잡한 조건의 경우 괄호를 사용하여 논리 단위를 분리할 수 있습니다. 다음 예에서는 조인 조건이 괄호로 묶여 있습니다.

```
where (category.catid=event.catid) and category.catid in(6,7,8)
```

## 사용 노트
<a name="r_WHERE_clause_usage_notes"></a>

select list 표현식을 참조하기 위해 WHERE 절의 별칭을 사용할 수 있습니다.

WHERE 절에서 집계 함수의 결과를 제한할 수 없습니다. 결과를 제한하려면 HAVING 절을 사용하십시오.

WHERE 절에서 제한되는 열은 FROM 절의 테이블 참조로부터 파생해야 합니다.

## 예제
<a name="r_SELECT_synopsis-example"></a>

다음 쿼리는 SALES 및 EVENT 테이블에 대한 조인 조건, EVENTNAME 열의 조건자, STARTTIME 열의 두 조건자를 비롯한 다양한 WHERE 절 제한 사항의 조합을 사용합니다.

```
select eventname, starttime, pricepaid/qtysold as costperticket, qtysold
from sales, event
where sales.eventid = event.eventid
and eventname='Hannah Montana'
and date_part(quarter, starttime) in(1,2)
and date_part(year, starttime) = 2008
order by 3 desc, 4, 2, 1 limit 10;

eventname    |      starttime      |   costperticket   | qtysold
----------------+---------------------+-------------------+---------
Hannah Montana | 2008-06-07 14:00:00 |     1706.00000000 |       2
Hannah Montana | 2008-05-01 19:00:00 |     1658.00000000 |       2
Hannah Montana | 2008-06-07 14:00:00 |     1479.00000000 |       1
Hannah Montana | 2008-06-07 14:00:00 |     1479.00000000 |       3
Hannah Montana | 2008-06-07 14:00:00 |     1163.00000000 |       1
Hannah Montana | 2008-06-07 14:00:00 |     1163.00000000 |       2
Hannah Montana | 2008-06-07 14:00:00 |     1163.00000000 |       4
Hannah Montana | 2008-05-01 19:00:00 |      497.00000000 |       1
Hannah Montana | 2008-05-01 19:00:00 |      497.00000000 |       2
Hannah Montana | 2008-05-01 19:00:00 |      497.00000000 |       4
(10 rows)
```

# WHERE 절의 Oracle 스타일 외부 조인
<a name="r_WHERE_oracle_outer"></a>

Oracle 호환성을 위해 Amazon Redshift는 WHERE 절 조인 조건에서 Oracle 외부 조인 연산자(\$1)를 지원합니다. 이 연산자는 외부 조인 조건을 정의하는 데만 사용하는 연산자이므로, 다른 컨텍스트에서는 사용하지 마십시오. 이 연산자를 달리 사용하면 대부분의 경우에는 자동으로 무시됩니다.

외부 조인은 동등한 내부 조인이 반환하는 모든 행과 한 테이블 또는 두 테이블 모두에서 일치하지 않는 행을 반환합니다. FROM 절에서 왼쪽, 오른쪽 및 전체 외부 조인을 지정할 수 있습니다. WHERE 절에서 왼쪽 및 오른쪽 외부 조인만 지정할 수 있습니다.

외부 조인 테이블 TABLE1 및 TABLE2를 지정하고 TABLE1(왼쪽 외부 조인)에서 일치하지 않는 행을 반환하려면 FROM 절에 `TABLE1 LEFT OUTER JOIN TABLE2`를 지정하거나 WHERE 절의 TABLE2에서 모든 조인 열에 (\$1) 연산자를 적용합니다. TABLE2에 일치하는 행이 없는 TABLE1의 모든 행에 대해, 쿼리의 결과는 TABLE2의 열을 포함한 모든 select list 표현식을 위한 null을 포함합니다.

TABLE1에 일치하는 행이 없는 TABLE2의 모든 행에 대해 동일한 동작을 생성하려면 FROM 절에 `TABLE1 RIGHT OUTER JOIN TABLE2`를 지정하거나 WHERE 절의 TABLE1에서 모든 조인 열에 (\$1) 연산자를 적용합니다.

## 기본 구문
<a name="r_WHERE_oracle_outer-basic-syntax"></a>

```
[ WHERE {
[ table1.column1 = table2.column1(+) ]
[ table1.column1(+) = table2.column1 ]
}
```

첫 번째 조건은 다음과 동등합니다.

```
from table1 left outer join table2
on table1.column1=table2.column1
```

두 번째 조건은 다음과 동등합니다.

```
from table1 right outer join table2
on table1.column1=table2.column1
```

**참고**  
여기에 표시된 구문은 한 쌍의 조인 열에 대해 간단한 동등 조인 케이스를 포함합니다. 하지만 다른 유형의 비교 조건과 여러 쌍의 조인 열 역시 유효합니다.

예를 들어, 다음 WHERE 절은 두 쌍의 열에 대해 외부 조인을 정의합니다. 두 조건에서 모두 (\$1) 연산자를 같은 테이블에 연결해야 합니다.

```
where table1.col1 > table2.col1(+)
and table1.col2 = table2.col2(+)
```

## 사용 노트
<a name="r_WHERE_oracle_outer_usage_notes"></a>

가능하면 WHERE 절에 (\$1) 연산자 대신 표준 FROM 절 OUTER JOIN 구문을 사용하십시오. (\$1) 연산자를 포함하는 쿼리는 다음 규칙에 따릅니다.
+ WHERE 절에는 (\$1) 연산자만 사용할 수 있고, 테이블 또는 뷰의 열에 대한 참조에만 사용할 수 있습니다.
+ 표현식에는 (\$1) 연산자를 적용할 수 없습니다. 하지만 표현식은 (\$1) 연산자를 사용하는 열을 포함할 수 있습니다. 예를 들어 다음과 같은 조인 조건은 구문 오류를 반환합니다.

  ```
  event.eventid*10(+)=category.catid
  ```

  그러나 다음 조인 조건이 유효합니다.

  ```
  event.eventid(+)*10=category.catid
  ```
+ FROM 절 조인 구문도 포함하는 쿼리 블록에 (\$1) 연산자를 사용할 수 없습니다.
+ 여러 조인 조건에 걸쳐 두 테이블이 조인되는 경우 이런 조건 전부에 (\$1) 연산자를 사용하거나 아무런 조건에도 이 연산자를 사용하면 안 됩니다. 혼합 구문 스타일의 조인은 따로 경고 없이 내부 조인으로 실행됩니다.
+ 외부 쿼리의 테이블을 내부 쿼리에서 생성되는 테이블과 조인하는 경우 (\$1) 연산자는 외부 조인을 생성하지 않습니다.
+ (\$1) 연산자를 사용하여 테이블을 그 자체에 외부 조인하려면 FROM 절에서 테이블 별칭을 정의하고 이런 별칭을 조인 조건에서 참조해야 합니다.

  ```
  select count(*)
  from event a, event b
  where a.eventid(+)=b.catid;
  
  count
  -------
  8798
  (1 row)
  ```
+ (\$1) 연산자를 포함하는 조인 조건을 OR 조건 또는 IN 조건과 결합할 수 없습니다. 예: 

  ```
  select count(*) from sales, listing
  where sales.listid(+)=listing.listid or sales.salesid=0;
  ERROR:  Outer join operator (+) not allowed in operand of OR or IN.
  ```
+  2개보다 많은 테이블을 외부 조인하는 WHERE 절에서는 (\$1) 연산자를 주어진 테이블에 한 번만 적용할 수 있습니다. 다음 예에서는 2개의 연속 조인에서 (\$1) 연산자로 SALES 테이블을 참조할 수 없습니다.

  ```
  select count(*) from sales, listing, event
  where sales.listid(+)=listing.listid and sales.dateid(+)=date.dateid;
  ERROR:  A table may be outer joined to at most one other table.
  ```
+  WHERE 절 외부 조인 조건이 TABLE2의 열을 상수와 비교하는 경우 그 열에 (\$1) 연산자를 적용합니다. 이 연산자를 포함하지 않으면 제한된 열을 위한 null을 포함하는 TABLE1의 외부 조인된 행이 제거됩니다. 아래 예시 섹션을 참조하세요.

## 예제
<a name="r_WHERE_oracle_outer-examples"></a>

다음 조인 쿼리는 LISTID 열에 대한 SALES 및 LISTING 테이블의 왼쪽 외부 조인을 지정합니다.

```
select count(*)
from sales, listing
where sales.listid = listing.listid(+);

count
--------
172456
(1 row)
```

위와 동등한 다음의 쿼리는 결과는 같지만 FROM 절 조인 구문을 사용합니다.

```
select count(*)
from sales left outer join listing on sales.listid = listing.listid;

count
--------
172456
(1 row)
```

SALES 테이블은 모든 목록이 판매로 이어지는 것은 아니므로 LISTING 테이블의 모든 목록에 대한 레코드를 포함하지는 않습니다. 다음 쿼리는 SALES와 LISTING을 외부 조인하고 SALES 테이블이 주어진 목록 ID에 대해 아무런 판매도 보고하지 않을 때도 LISTING에서 행을 반환합니다. SALES 테이블에서 파생되는 PRICE 및 COMM 열은 일치하지 않는 행에 대한 결과 집합에 null이 있습니다.

```
select listing.listid, sum(pricepaid) as price,
sum(commission) as comm
from listing, sales
where sales.listid(+) = listing.listid and listing.listid between 1 and 5
group by 1 order by 1;

listid | price  |  comm
--------+--------+--------
1 | 728.00 | 109.20
2 |        |
3 |        |
4 |  76.00 |  11.40
5 | 525.00 |  78.75
(5 rows)
```

WHERE 절 조인 연산자가 사용될 때 FROM 절에서 테이블의 순서는 중요하지 않습니다.

WHERE 절에서 더 복잡한 외부 조인 조건의 예시는 조건이 두 테이블 열 사이의 비교 *and* 상수와의 비교로 구성되는 경우입니다.

```
where category.catid=event.catid(+) and eventid(+)=796;
```

(\$1) 연산자는 두 곳에 사용되는데, 첫째로는 테이블 사이의 동등성 비교에 사용되고 둘째로는 EVENTID 열에 대한 비교 조건에 사용됩니다. 이 구문의 결과는 EVENTID에 대한 제한이 평가될 때 외부 조인된 행이 보존되는 것입니다. EVENTID 제한에서 (\$1) 연산자를 제거하는 경우 쿼리는 이 제한을 외부 조인 조건의 일부가 아니라 필터로 취급합니다. 그러면 EVENTID에 대해 null을 포함하는 외부 조인된 행이 결과 집합에서 제거됩니다.

다음은 이 동작을 설명하는 완전한 쿼리입니다.

```
select catname, catgroup, eventid
from category, event
where category.catid=event.catid(+) and eventid(+)=796;

catname | catgroup | eventid
-----------+----------+---------
Classical | Concerts |
Jazz | Concerts |
MLB | Sports   |
MLS | Sports   |
Musicals | Shows    | 796
NBA | Sports   |
NFL | Sports   |
NHL | Sports   |
Opera | Shows    |
Plays | Shows    |
Pop | Concerts |
(11 rows)
```

FROM 절 구문을 사용하는 동등한 쿼리는 다음과 같습니다.

```
select catname, catgroup, eventid
from category left join event
on category.catid=event.catid and eventid=796;
```

이 쿼리의 WHERE 절 버전에서 두 번째 (\$1) 연산자를 제거하는 경우 1개의 행만 반환합니다(`eventid=796`인 행).

```
select catname, catgroup, eventid
from category, event
where category.catid=event.catid(+) and eventid=796;

catname | catgroup | eventid
-----------+----------+---------
Musicals | Shows    | 796
(1 row)
```

# GROUP BY 절
<a name="r_GROUP_BY_clause"></a>

GROUP BY 절은 쿼리에 대한 그룹화 열을 식별합니다. 이는 테이블에서 나열된 모든 열에 같은 값이 있는 행을 그룹화하는 데 사용됩니다. 열이 나열된 순서는 중요하지 않습니다. 결과는 공통 값을 가진 각 행 세트를 그룹의 모든 행을 나타내는 하나의 그룹 행으로 결합하는 것입니다. GROUP BY를 사용하여 출력의 중복을 제거하고 그룹에 적용되는 집계를 계산합니다. 쿼리가 SUM, AVG 및 COUNT와 같은 표준 함수로 집계를 계산할 때 그룹화 열을 선언해야 합니다. 자세한 내용은 [집계 함수](c_Aggregate_Functions.md) 섹션을 참조하세요.

## 구문
<a name="r_GROUP_BY_clause-syntax"></a>

```
[ GROUP BY  expression [, ...] | ALL | aggregation_extension  ]
```

여기서 *aggregation\$1extension*은 다음 중 하나입니다.

```
GROUPING SETS ( () | aggregation_extension [, ...] ) |
ROLLUP ( expr [, ...] ) |
CUBE ( expr [, ...] )
```

## 파라미터
<a name="r_GROUP_BY_clause-parameters"></a>

 * expression*  
열 또는 표현식의 목록은 쿼리의 선택 목록에 있는 비집계 표현식의 목록과 일치해야 합니다. 예를 들어, 다음과 같이 간단한 쿼리를 생각해 보세요.  

```
select listid, eventid, sum(pricepaid) as revenue,
count(qtysold) as numtix
from sales
group by listid, eventid
order by 3, 4, 2, 1
limit 5;

listid | eventid | revenue | numtix
-------+---------+---------+--------
89397  |      47 |   20.00 |      1
106590 |      76 |   20.00 |      1
124683 |     393 |   20.00 |      1
103037 |     403 |   20.00 |      1
147685 |     429 |   20.00 |      1
(5 rows)
```
이 쿼리에서 선택 목록은 2개의 집계 표현식으로 구성됩니다. 첫 번째 표현식은 SUM 함수를 사용하고 두 번째 표현식은 COUNT 함수를 사용합니다. 나머지 두 개의 열 LISTID 및 EVENTID를 그룹화 열로 선언해야 합니다.  
GROUP BY 절에서 표현식은 서수를 사용하여 선택 목록을 참조할 수도 있습니다. 예를 들어, 이전 예는 다음과 같이 줄일 수도 있습니다.  

```
select listid, eventid, sum(pricepaid) as revenue,
count(qtysold) as numtix
from sales
group by 1,2
order by 3, 4, 2, 1
limit 5;

listid | eventid | revenue | numtix
-------+---------+---------+--------
89397  |      47 |   20.00 |      1
106590 |      76 |   20.00 |      1
124683 |     393 |   20.00 |      1
103037 |     403 |   20.00 |      1
147685 |     429 |   20.00 |      1
(5 rows)
```

ALL  
ALL은 집계된 열을 제외하고 SELECT 목록에 지정된 모든 열을 기준으로 그룹화함을 나타냅니다. 예를 들어 GROUP BY 절에서 개별적으로 지정할 필요 없이 `col1` 및 `col2`를 기준으로 그룹화하는 다음 쿼리를 생각해 보겠습니다. `col3` 열은 `SUM` 함수의 인수이므로 그룹화되지 않습니다.  

```
SELECT col1, col2 sum(col3) FROM testtable GROUP BY ALL
```
SELECT 목록에서 열을 제외하면 GROUP BY ALL 절은 해당 특정 열을 기반으로 결과를 그룹화하지 않습니다.  

```
SELECT * EXCLUDE col3 FROM testtable GROUP BY ALL
```

 * *aggregation\$1extension* *   
집계 확장 GROUPING SETS, ROLLUP 및 CUBE를 사용하여 단일 문에서 여러 GROUP BY 작업을 수행할 수 있습니다. 집계 확장 및 관련 기능에 대한 자세한 내용은 [집계 확장](r_GROUP_BY_aggregation-extensions.md)을 참조하세요.

## 예제
<a name="r_GROUP_BY_clause-examples"></a>

다음 예에서는 salesid, listid, sellerid, buyerid, eventid, dateid, qtysold, pricepaid, commission, saletime 열이 포함된 SALES 테이블을 사용합니다. SALES 테이블에 대한 자세한 내용은 [샘플 데이터베이스](c_sampledb.md) 섹션을 참조하세요.

다음 예시 쿼리는 GROUP BY 절에서 개별적으로 지정할 필요 없이 `salesid` 및 `listid`를 기준으로 그룹화합니다. `qtysold` 열은 `SUM` 함수의 인수이므로 그룹화되지 않습니다.

```
SELECT salesid, listid, sum(qtysold) FROM sales GROUP BY ALL;

salesid | listid  | sum
--------+---------+------
33095   | 36572   | 2	
88268   | 100813  | 4	
110917  | 127048  | 1	
...
```

다음 예시 쿼리는 SELECT 목록에서 여러 열을 제외하므로 GROUP BY ALL은 salesid와 listid만 그룹화합니다.

```
SELECT * EXCLUDE sellerid, buyerid, eventid, dateid, qtysold, pricepaid, commission, saletime 
FROM sales GROUP BY ALL;

salesid | listid 
--------+---------
33095   | 36572   	
88268   | 100813 	
110917  | 127048 	
...
```

# 집계 확장
<a name="r_GROUP_BY_aggregation-extensions"></a>

Amazon Redshift는 단일 문에서 여러 GROUP BY 작업을 수행하는 집계 확장을 지원합니다.

 집계 확장의 예시에서는 전자 회사의 판매 데이터가 들어 있는`orders` 테이블을 사용합니다. 다음을 사용하여 `orders`를 생성할 수 있습니다.

```
CREATE TABLE ORDERS (
    ID INT,
    PRODUCT CHAR(20),
    CATEGORY CHAR(20),
    PRE_OWNED CHAR(1),
    COST DECIMAL
);

INSERT INTO ORDERS VALUES
    (0, 'laptop',       'computers',    'T', 1000),
    (1, 'smartphone',   'cellphones',   'T', 800),
    (2, 'smartphone',   'cellphones',   'T', 810),
    (3, 'laptop',       'computers',    'F', 1050),
    (4, 'mouse',        'computers',    'F', 50);
```

## *GROUPING SETS*
<a name="r_GROUP_BY_aggregation-extensions-grouping-sets"></a>

 단일 명령문에서 하나 이상의 그룹화 집합을 계산합니다. 그룹화 집합은 쿼리의 결과 집합을 그룹화할 수 있는 0개 이상의 열 집합인 단일 GROUP BY 절의 집합입니다. 집합을 그룹화하여 그룹화하는 것은 서로 다른 열로 그룹화된 하나의 결과 집합에서 UNION ALL 쿼리를 실행하는 것과 같습니다. 예를 들어, GROUP BY GROUPING SETS((a), (b))는 GROUP BY a UNION ALL GROUP BY b와 동일합니다.

 다음 예에서는 제품 카테고리와 판매된 제품 종류에 따라 그룹화된 주문 테이블 제품의 비용을 반환합니다.

```
SELECT category, product, sum(cost) as total
FROM orders
GROUP BY GROUPING SETS(category, product);

       category       |       product        | total
----------------------+----------------------+-------
 computers            |                      |  2100
 cellphones           |                      |  1610
                      | laptop               |  2050
                      | smartphone           |  1610
                      | mouse                |    50

(5 rows)
```

## *ROLLUP*
<a name="r_GROUP_BY_aggregation-extensions-rollup"></a>

 이전 열이 후속 열의 부모로 간주되는 계층 구조를 가정합니다. ROLLUP은 제공된 열을 기준으로 데이터를 그룹화하여 그룹화된 행 외에 그룹화 열의 모든 수준에서 총계를 나타내는 추가 소계 행을 반환합니다. 예를 들어 GROUP BY ROLLUP ((a), (b) 를 사용하여 b가 a의 하위 섹션이라고 가정하면서 먼저 a로 그룹화된 다음 b로 그룹화된 결과 집합을 반환할 수 있습니다. ROLLUP은 또한 열을 그룹화하지 않고 전체 결과 집합이 있는 행을 반환합니다.

GROUP BY ROLLUP((a), (b))는 GROUP BY GROUPING SETS((a,b), (a), ())와 같습니다.

다음 예는 먼저 범주별로 그룹화된 주문 테이블의 제품 비용을 반환한 다음 제품을 범주의 하위 부문으로 사용하여 반환합니다.

```
SELECT category, product, sum(cost) as total
FROM orders
GROUP BY ROLLUP(category, product) ORDER BY 1,2;

       category       |       product        | total
----------------------+----------------------+-------
 cellphones           | smartphone           |  1610
 cellphones           |                      |  1610
 computers            | laptop               |  2050
 computers            | mouse                |    50
 computers            |                      |  2100
                      |                      |  3710
(6 rows)
```

## *CUBE*
<a name="r_GROUP_BY_aggregation-extensions-cube"></a>

 제공된 열을 기준으로 데이터를 그룹화하여 그룹화된 행 외에 그룹화 열의 모든 수준에서 합계를 나타내는 추가 소계 행을 반환합니다. CUBE는 ROLLUP과 동일한 행을 반환하는 동시에 ROLLUP에서 다루지 않는 그룹화 열의 모든 조합에 대해 소계 행을 추가합니다. 예를 들어 GROUP BY CUBE ((a), (b) 를 사용하여 b가 a의 하위 섹션이고 그 다음 b만으로 그룹화된 결과 집합을 반환할 수 있습니다. CUBE는 또한 열을 그룹화하지 않고 전체 결과 집합이 있는 행을 반환합니다.

GROUP BY CUBE((a), (b))는 GROUP BY GROUPING SETS((a, b), (a), (b), ())와 같습니다.

다음 예는 먼저 범주별로 그룹화된 주문 테이블의 제품 비용을 반환한 다음 제품을 범주의 하위 부문으로 사용하여 반환합니다. ROLLUP에 대한 앞의 예와 달리 문은 그룹화 열의 모든 조합에 대한 결과를 반환합니다.

```
SELECT category, product, sum(cost) as total
FROM orders
GROUP BY CUBE(category, product) ORDER BY 1,2;

       category       |       product        | total
----------------------+----------------------+-------
 cellphones           | smartphone           |  1610
 cellphones           |                      |  1610
 computers            | laptop               |  2050
 computers            | mouse                |    50
 computers            |                      |  2100
                      | laptop               |  2050
                      | mouse                |    50
                      | smartphone           |  1610
                      |                      |  3710
(9 rows)
```

## *GROUPING/GROUPING\$1ID 함수*
<a name="r_GROUP_BY_aggregation-extentions-grouping"></a>

 ROLLUP 및 CUBE는 소계 행을 나타내기 위해 결과 집합에 NULL 값을 추가합니다. 예를 들어 GROUP BY ROLLUP((a), (b))는 b 그룹화 열에서 값이 NULL인 하나 이상의 행을 반환하여 그룹화 열에 있는 필드의 소계임을 나타냅니다. 이러한 NULL 값은 반환 튜플의 형식을 충족하는 데만 사용됩니다.

 NULL 값 자체를 저장하는 관계에서 ROLLUP 및 CUBE와 함께 GROUP BY 작업을 실행하면 동일한 그룹화 열이 있는 것으로 보이는 행이 있는 결과 집합이 생성될 수 있습니다. 이전 예제로 돌아가서 b 그룹화 열에 저장된 NULL 값이 포함된 경우 GROUP BY ROLLUP ((a), (b) 은 b 그룹화 열에서 소계가 아닌 값이 NULL인 행을 반환합니다.

 ROLLUP 및 CUBE에 의해 생성된 NULL 값과 테이블 자체에 저장된 NULL 값을 구별하기 위해 GROUPING 함수 또는 별칭 GROUPING\$1ID를 사용할 수 있습니다. GROUPING은 단일 그룹화 집합을 인수로 사용하고 결과 집합의 각 행에 대해 해당 위치의 그룹화 열에 해당하는 0 또는 1비트 값을 반환한 다음 해당 값을 정수로 변환합니다. 해당 위치의 값이 집계 확장에 의해 생성된 NULL 값인 경우 GROUPING은 1을 반환합니다. 이 함수는 저장된 NULL 값을 비롯해 다른 모든 값에 대해 0을 반환합니다.

 예를 들어 GROUPING(category, product)은 해당 행의 그룹화 열 값에 따라 지정된 행에 대해 다음 값을 반환할 수 있습니다. 이 예제의 목적을 위해 테이블의 모든 NULL 값은 집계 확장에 의해 생성된 NULL 값입니다.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/redshift/latest/dg/r_GROUP_BY_aggregation-extensions.html)

GROUPING 함수는 쿼리의 SELECT 목록 부분에 다음 형식으로 나타납니다.

```
SELECT ... [GROUPING( expr )...] ...
  GROUP BY ... {CUBE | ROLLUP| GROUPING SETS} ( expr ) ...
```

다음 예제는 CUBE에 대한 이전 예제와 동일하지만 그룹화 집합에 대한 GROUPING 함수가 추가되었습니

```
SELECT category, product,
       GROUPING(category) as grouping0,
       GROUPING(product) as grouping1,
       GROUPING(category, product) as grouping2,
       sum(cost) as total
FROM orders
GROUP BY CUBE(category, product) ORDER BY 3,1,2;

       category       |       product        | grouping0 | grouping1 | grouping2 | total
----------------------+----------------------+-----------+-----------+-----------+-------
 cellphones           | smartphone           |         0 |         0 |         0 |  1610
 cellphones           |                      |         0 |         1 |         1 |  1610
 computers            | laptop               |         0 |         0 |         0 |  2050
 computers            | mouse                |         0 |         0 |         0 |    50
 computers            |                      |         0 |         1 |         1 |  2100
                      | laptop               |         1 |         0 |         2 |  2050
                      | mouse                |         1 |         0 |         2 |    50
                      | smartphone           |         1 |         0 |         2 |  1610
                      |                      |         1 |         1 |         3 |  3710
(9 rows)
```

## *부분 ROLLUP 및 CUBE*
<a name="r_GROUP_BY_aggregation-extentions-partial"></a>

 소계의 일부만으로 ROLLUP 및 CUBE 작업을 실행할 수 있습니다.

 부분 ROLLUP 및 CUBE 작업의 구문은 다음과 같습니다.

```
GROUP BY expr1, { ROLLUP | CUBE }(expr2, [, ...])
```

여기에서 GROUP BY 절은 *expr2* 이후의 수준에서 소계 행만 생성합니다.

다음 예제는 주문 테이블에 대한 부분 ROLLUP 및 CUBE 작업을 보여줍니다. 먼저 제품이 중고인지 여부에 따라 그룹화한 다음 범주 및 제품 열에서 ROLLUP 및 CUBE를 실행합니다.

```
SELECT pre_owned, category, product,
       GROUPING(category, product, pre_owned) as group_id,
       sum(cost) as total
FROM orders
GROUP BY pre_owned, ROLLUP(category, product) ORDER BY 4,1,2,3;

 pre_owned |       category       |       product        | group_id | total
-----------+----------------------+----------------------+----------+-------
 F         | computers            | laptop               |        0 |  1050
 F         | computers            | mouse                |        0 |    50
 T         | cellphones           | smartphone           |        0 |  1610
 T         | computers            | laptop               |        0 |  1000
 F         | computers            |                      |        2 |  1100
 T         | cellphones           |                      |        2 |  1610
 T         | computers            |                      |        2 |  1000
 F         |                      |                      |        6 |  1100
 T         |                      |                      |        6 |  2610
(9 rows)

SELECT pre_owned, category, product,
       GROUPING(category, product, pre_owned) as group_id,
       sum(cost) as total
FROM orders
GROUP BY pre_owned, CUBE(category, product) ORDER BY 4,1,2,3;

 pre_owned |       category       |       product        | group_id | total
-----------+----------------------+----------------------+----------+-------
 F         | computers            | laptop               |        0 |  1050
 F         | computers            | mouse                |        0 |    50
 T         | cellphones           | smartphone           |        0 |  1610
 T         | computers            | laptop               |        0 |  1000
 F         | computers            |                      |        2 |  1100
 T         | cellphones           |                      |        2 |  1610
 T         | computers            |                      |        2 |  1000
 F         |                      | laptop               |        4 |  1050
 F         |                      | mouse                |        4 |    50
 T         |                      | laptop               |        4 |  1000
 T         |                      | smartphone           |        4 |  1610
 F         |                      |                      |        6 |  1100
 T         |                      |                      |        6 |  2610
(13 rows)
```

사전 소유 열은 ROLLUP 및 CUBE 작업에 포함되지 않으므로 다른 모든 행을 포함하는 총계 행이 없습니다.

## *연결된 그룹화*
<a name="r_GROUP_BY_aggregation-extentions-concat"></a>

 여러 GROUPING SETS/ROLLUP/CUBE 절을 연결하여 서로 다른 수준의 소계를 계산할 수 있습니다. 연결된 그룹화는 제공된 그룹화 집합의 데카르트 곱을 반환합니다.

 GROUPING SETS/ROLLUP/CUBE 절을 연결하는 구문은 다음과 같습니다.

```
GROUP BY {ROLLUP|CUBE|GROUPING SETS}(expr1[, ...]),
         {ROLLUP|CUBE|GROUPING SETS}(expr1[, ...])[, ...]
```

다음 예제를 통해 서로 연결된 소규모 그룹화가 어떻게 큰 최종 결과 집합을 생성할 수 있는지 확인해 보세요.

```
SELECT pre_owned, category, product,
       GROUPING(category, product, pre_owned) as group_id,
       sum(cost) as total
FROM orders
GROUP BY CUBE(category, product), GROUPING SETS(pre_owned, ())
ORDER BY 4,1,2,3;

 pre_owned |       category       |       product        | group_id | total
-----------+----------------------+----------------------+----------+-------
 F         | computers            | laptop               |        0 |  1050
 F         | computers            | mouse                |        0 |    50
 T         | cellphones           | smartphone           |        0 |  1610
 T         | computers            | laptop               |        0 |  1000
           | cellphones           | smartphone           |        1 |  1610
           | computers            | laptop               |        1 |  2050
           | computers            | mouse                |        1 |    50
 F         | computers            |                      |        2 |  1100
 T         | cellphones           |                      |        2 |  1610
 T         | computers            |                      |        2 |  1000
           | cellphones           |                      |        3 |  1610
           | computers            |                      |        3 |  2100
 F         |                      | laptop               |        4 |  1050
 F         |                      | mouse                |        4 |    50
 T         |                      | laptop               |        4 |  1000
 T         |                      | smartphone           |        4 |  1610
           |                      | laptop               |        5 |  2050
           |                      | mouse                |        5 |    50
           |                      | smartphone           |        5 |  1610
 F         |                      |                      |        6 |  1100
 T         |                      |                      |        6 |  2610
           |                      |                      |        7 |  3710
(22 rows)
```

## *중첩된 그룹화*
<a name="r_GROUP_BY_aggregation-extentions-nested"></a>

 GROUPING SETS/ROLLUP/CUBE 작업을 GROUPING SETS *expr*로 사용하여 중첩된 그룹화를 형성할 수 있습니다. 중첩된 GROUPING SETS 내부의 하위 그룹화가 평면화됩니다.

 중첩된 그룹화의 구문은 다음과 같습니다.

```
GROUP BY GROUPING SETS({ROLLUP|CUBE|GROUPING SETS}(expr[, ...])[, ...])
```

다음 예제를 살펴보세요.

```
SELECT category, product, pre_owned,
       GROUPING(category, product, pre_owned) as group_id,
       sum(cost) as total
FROM orders
GROUP BY GROUPING SETS(ROLLUP(category), CUBE(product, pre_owned))
ORDER BY 4,1,2,3;

       category       |       product        | pre_owned | group_id | total
----------------------+----------------------+-----------+----------+-------
 cellphones           |                      |           |        3 |  1610
 computers            |                      |           |        3 |  2100
                      | laptop               | F         |        4 |  1050
                      | laptop               | T         |        4 |  1000
                      | mouse                | F         |        4 |    50
                      | smartphone           | T         |        4 |  1610
                      | laptop               |           |        5 |  2050
                      | mouse                |           |        5 |    50
                      | smartphone           |           |        5 |  1610
                      |                      | F         |        6 |  1100
                      |                      | T         |        6 |  2610
                      |                      |           |        7 |  3710
                      |                      |           |        7 |  3710
(13 rows)
```

ROLLUP(category) 및 CUBE(product, pre\$1owned) 모두 그룹화 집합()을 포함하므로 총계를 나타내는 행이 중복됩니다.

## *사용 노트*
<a name="r_GROUP_BY_aggregation-extensions-usage-notes"></a>
+ GROUP BY 절은 최대 64개의 그룹화 세트를 지원합니다. ROLLUP 및 CUBE 또는 GROUPING SETS, ROLLUP 및 CUBE의 일부 조합의 경우 이 제한은 포함된 그룹화 집합 수에 적용됩니다. 예를 들어 GROUP BY CUBE((a), (b))는 2가 아닌 4개의 그룹화 집합으로 계산됩니다.
+ 집계 확장을 사용하는 경우 상수를 그룹화 열로 사용할 수 없습니다.
+ 중복된 열이 포함된 그룹화 집합은 만들 수 없습니다.

# HAVING 절
<a name="r_HAVING_clause"></a>

HAVING 절은 쿼리가 반환하는 중간 그룹화 결과 집합에 조건을 적용합니다.

## 구문
<a name="r_HAVING_clause-synopsis"></a>

```
[ HAVING condition ]
```

예를 들어, SUM 함수의 결과를 제한할 수 있습니다.

```
having sum(pricepaid) >10000
```

모든 WHERE 절 조건이 적용되고 GROUP BY 작업이 완료된 후 HAVING 조건이 적용됩니다.

조건 자체는 WHERE 절 조건과 같은 형식을 취합니다.

## 사용 노트
<a name="r_HAVING_clause_usage_notes"></a>
+ HAVING 절 조건에서 참조되는 열은 그룹화 열이거나 집계 함수의 결과를 참조하는 열이어야 합니다.
+ HAVING 절에서 다음을 지정할 수는 없습니다.
  + 선택 목록 항목을 참조하는 서수. GROUP BY 및 ORDER BY 절만이 서수를 허용합니다.

## 예제
<a name="r_HAVING_clause-examples"></a>

다음 쿼리는 이름을 기준으로 모든 이벤트에 대한 총 티켓 판매액을 계산한 다음, 총 판매액이 \$1800,000 미만인 이벤트를 제거합니다. HAVING 조건은 선택 목록에서 집계 함수의 결과에 적용됩니다. `sum(pricepaid)`.

```
select eventname, sum(pricepaid)
from sales join event on sales.eventid = event.eventid
group by 1
having sum(pricepaid) > 800000
order by 2 desc, 1;

eventname        |    sum
-----------------+-----------
Mamma Mia!       | 1135454.00
Spring Awakening |  972855.00
The Country Girl |  910563.00
Macbeth          |  862580.00
Jersey Boys      |  811877.00
Legally Blonde   |  804583.00
```

다음 쿼리는 비슷한 결과 집합을 계산합니다. 하지만 이 경우에는 HAVING 조건이 선택 목록에 지정되지 않은 집계에 적용됩니다(`sum(qtysold)`). 티켓이 2,000장보다 많이 팔리지 않은 이벤트가 최종 결과에서 제거됩니다.

```
select eventname, sum(pricepaid)
from sales join event on sales.eventid = event.eventid
group by 1
having sum(qtysold) >2000
order by 2 desc, 1;

eventname        |    sum
-----------------+-----------
Mamma Mia!       | 1135454.00
Spring Awakening |  972855.00
The Country Girl |  910563.00
Macbeth          |  862580.00
Jersey Boys      |  811877.00
Legally Blonde   |  804583.00
Chicago          |  790993.00
Spamalot         |  714307.00
```

다음 쿼리는 이름을 기준으로 모든 이벤트에 대한 총 티켓 판매액을 계산한 다음, 총 판매액이 \$1800,000 미만인 이벤트를 제거합니다. HAVING 조건은 선택 목록에서 `sum(pricepaid)`에 별칭 `pp`를 사용하여 집계 함수의 결과에 적용됩니다.

```
select eventname, sum(pricepaid) as pp
from sales join event on sales.eventid = event.eventid
group by 1
having pp > 800000
order by 2 desc, 1;

eventname        |    pp
-----------------+-----------
Mamma Mia!       | 1135454.00
Spring Awakening |  972855.00
The Country Girl |  910563.00
Macbeth          |  862580.00
Jersey Boys      |  811877.00
Legally Blonde   |  804583.00
```

# QUALIFY 절
<a name="r_QUALIFY_clause"></a>

QUALIFY 절은 사용자가 지정한 검색 조건에 따라 이전에 계산된 윈도우 함수의 결과를 필터링합니다. 이 절을 사용하면 하위 쿼리를 사용하지 않고 윈도우 함수의 결과에 필터링 조건을 적용할 수 있습니다.

이는 조건을 적용하여 WHERE 절의 행을 추가로 필터링하는 [HAVING 절](https://docs.aws.amazon.com/redshift/latest/dg/r_HAVING_clause.html)과 유사합니다. QUALIFY와 HAVING의 차이점은 QUALIFY 절의 필터링된 결과가 데이터에 대해 윈도우 함수를 실행한 결과를 기반으로 할 수 있다는 것입니다. 한 쿼리에서 QUALIFY 절과 HAVING 절을 모두 사용할 수 있습니다.

## 구문
<a name="r_QUALIFY-synopsis"></a>

```
QUALIFY condition
```

**참고**  
FROM 절 바로 뒤에 QUALIFY 절을 사용하는 경우 FROM 관계 이름에는 QUALIFY 절 앞에 별칭이 지정되어 있어야 합니다.

## 예제
<a name="r_QUALIFY-examples"></a>

이 섹션의 예에서는 아래 샘플 데이터를 사용합니다.

```
create table store_sales (ss_sold_date date, ss_sold_time time, 
               ss_item text, ss_sales_price float);
insert into store_sales values ('2022-01-01', '09:00:00', 'Product 1', 100.0),
                               ('2022-01-01', '11:00:00', 'Product 2', 500.0),
                               ('2022-01-01', '15:00:00', 'Product 3', 20.0),
                               ('2022-01-01', '17:00:00', 'Product 4', 1000.0),
                               ('2022-01-01', '18:00:00', 'Product 5', 30.0),
                               ('2022-01-02', '10:00:00', 'Product 6', 5000.0),
                               ('2022-01-02', '16:00:00', 'Product 7', 5.0);
```

다음 예는 매일 12:00 이후에 판매된 가장 비싼 품목 두 개를 찾는 방법을 보여줍니다.

```
SELECT *
FROM store_sales ss
WHERE ss_sold_time > time '12:00:00'
QUALIFY row_number()
OVER (PARTITION BY ss_sold_date ORDER BY ss_sales_price DESC) <= 2
               

 ss_sold_date | ss_sold_time |  ss_item  | ss_sales_price 
--------------+--------------+-----------+----------------
 2022-01-01   | 17:00:00     | Product 4 |           1000
 2022-01-01   | 18:00:00     | Product 5 |             30
 2022-01-02   | 16:00:00     | Product 7 |              5
```

그런 다음 매일 마지막으로 판매된 품목을 찾을 수 있습니다.

```
SELECT *
FROM store_sales ss
QUALIFY last_value(ss_item)
OVER (PARTITION BY ss_sold_date ORDER BY ss_sold_time ASC
      ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) = ss_item;
               
ss_sold_date | ss_sold_time |  ss_item  | ss_sales_price 
--------------+--------------+-----------+----------------
 2022-01-01   | 18:00:00     | Product 5 |             30
 2022-01-02   | 16:00:00     | Product 7 |              5
```

다음 예에서는 이전 쿼리와 동일한 레코드, 즉 매일 마지막으로 판매된 품목을 반환하지만 QUALIFY 절을 사용하지 않습니다.

```
SELECT * FROM (
  SELECT *,
  last_value(ss_item)
  OVER (PARTITION BY ss_sold_date ORDER BY ss_sold_time ASC
        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) ss_last_item
  FROM store_sales ss
)
WHERE ss_last_item = ss_item;
               
 ss_sold_date | ss_sold_time |  ss_item  | ss_sales_price | ss_last_item 
--------------+--------------+-----------+----------------+--------------
 2022-01-02   | 16:00:00     | Product 7 |              5 | Product 7
 2022-01-01   | 18:00:00     | Product 5 |             30 | Product 5
```

# UNION, INTERSECT 및 EXCEPT
<a name="r_UNION"></a>

**Topics**
+ [구문](#r_UNION-synopsis)
+ [파라미터](#r_UNION-parameters)
+ [설정 연산자에 대한 평가 순서](#r_UNION-order-of-evaluation-for-set-operators)
+ [사용 노트](#r_UNION-usage-notes)
+ [UNION 쿼리 예](c_example_union_query.md)
+ [UNION ALL 쿼리 예](c_example_unionall_query.md)
+ [INTERSECT 쿼리 예](c_example_intersect_query.md)
+ [EXCEPT 쿼리 예](c_Example_MINUS_query.md)

UNION, INTERSECT 및 EXCEPT *설정 연산자*는 별개의 두 쿼리 표현식의 결과를 비교 및 병합하는 데 사용됩니다. 예를 들어, 웹사이트의 어떤 사용자가 구매자인 동시에 판매자인지 알고 싶지만 이런 사용자들의 사용자 이름이 별개의 열이나 테이블에 저장되어 있는 경우 이러한 두 가지 사용자 유형의 *교집합*을 찾을 수 있습니다. 어떤 웹사이트 사용자가 구매자이고 판매자는 아닌지 알고 싶으면 EXCEPT 연산자를 사용하여 두 사용자 목록 사이의 *차이*를 찾을 수 있습니다. 역할과는 상관없이 모든 사용자의 목록을 빌드하려면 UNION 연산자를 사용할 수 있습니다.

## 구문
<a name="r_UNION-synopsis"></a>

```
query
{ UNION [ ALL ] | INTERSECT | EXCEPT | MINUS }
query
```

## 파라미터
<a name="r_UNION-parameters"></a>

 *query*()   
UNION, INTERSECT 또는 EXCEPT 연산자 뒤에 쿼리 표현식의 선택 목록 형태로 제2의 쿼리 표현식에 상응하는 쿼리 표현식입니다. 이 두 표현식에는 호환 데이터 형식을 가진 같은 개수의 출력 열이 있어야 합니다. 그렇지 않으면 두 결과 집합을 비교 및 병합할 수 없습니다. 설정 연산은 서로 다른 범주의 데이터 형식 간의 암시적 변환을 허용하지 않습니다. 자세한 내용은 [형식 호환성 및 변환](c_Supported_data_types.md#r_Type_conversion) 섹션을 참조하세요.  
무제한 개수의 쿼리 표현식을 포함하는 쿼리를 빌드하고 임의의 조합으로 UNION, INTERSECT 및 EXCEPT 연산자와 연결할 수 있습니다. 예를 들어, 테이블 T1, T2 및 T3에 호환되는 열 집합이 포함되어 있다고 가정하면 다음 쿼리 구조가 유효합니다.  

```
select * from t1
union
select * from t2
except
select * from t3
order by c1;
```

UNION   
행이 한 표현식이나 두 표현식 모두에서 파생하는지에 상관없이, 두 쿼리 표현식에서 행을 반환하는 작업을 설정합니다.

INTERSECT   
두 쿼리 표현식에서 파생하는 행을 반환하는 작업을 설정합니다. 두 표현식에서 모두 반환되지 않는 행은 삭제됩니다.

EXCEPT \$1 MINUS   
두 쿼리 표현식 중 하나에서 파생하는 행을 반환하는 작업을 설정합니다. 첫 번째 결과 테이블에는 있지만 두 번째 결과 테이블에는 없는 행에 대한 결과가 반환될 수 있다. MINUS 및 EXCEPT는 정확히 동의어입니다.

ALL   
ALL 키워드는 UNION에 의해 생성되는 중복 행을 모두 유지합니다. ALL 키워드가 사용되지 않을 때의 기본 동작은 이러한 중복 항목을 삭제하는 것입니다. INTERSECT ALL, EXCEPT ALL 및 MINUS ALL은 지원되지 않습니다.

## 설정 연산자에 대한 평가 순서
<a name="r_UNION-order-of-evaluation-for-set-operators"></a>

UNION 및 EXCEPT 설정 연산자는 좌우선 결합 연산자입니다. 우선순위에 영향을 주기 위해 괄호가 지정되어 있지 않은 경우 이러한 설정 연산자의 조합은 왼쪽에서 오른쪽으로 계산됩니다. 예를 들어 다음 쿼리에서, T1 및 T2의 UNION이 먼저 계산된 다음 UNION 결과에 대해 EXCEPT 작업이 수행됩니다.

```
select * from t1
union
select * from t2
except
select * from t3
order by c1;
```

동일한 쿼리에 연산자 조합이 사용될 때 INTERSECT 연산자가 UNION 및 EXCEPT 연산자보다 우선합니다. 예를 들어 다음 쿼리는 T2 및 T3의 교집합을 계산한 다음 그 결과와 T1의 합집합을 구합니다.

```
select * from t1
union
select * from t2
intersect
select * from t3
order by c1;
```

괄호를 추가하면 다른 계산 순서를 적용할 수 있습니다. 다음 경우에는 T1 및 T2의 합집합 결과가 T3와 교집합을 이루고, 쿼리가 다른 결과를 낳을 가능성이 있습니다.

```
(select * from t1
union
select * from t2)
intersect
(select * from t3)
order by c1;
```

## 사용 노트
<a name="r_UNION-usage-notes"></a>
+ 설정 작업 쿼리의 결과에 반환되는 열 이름은 첫 번째 쿼리 표현식의 테이블에서 가져온 열 이름(또는 별칭)입니다. 열의 값이 설정 연산자의 어느 한쪽에 있는 테이블에서 파생한다는 점에서 이런 열 이름은 오해를 불러일으킬 가능성이 있으므로, 결과 집합에 대해 의미 있는 별칭을 부여하고 싶을 수도 있습니다.
+ 설정 연산자에 선행하는 쿼리 표현식에 ORDER BY 절을 포함하면 안 됩니다. ORDER BY 절은 설정 연산자를 포함하는 쿼리의 끝에 사용될 때만 의미 있게 정렬된 결과를 내놓습니다. 이 경우에는 ORDER BY 절이 모든 설정 작업의 최종 결과에 적용됩니다. 가장 바깥쪽 쿼리는 표준 LIMIT 및 OFFSET 절도 포함할 수 있습니다.
+ 설정 연산자 쿼리가 10진수 결과를 반환할 때 그에 상응하는 결과 열은 같은 정밀도와 규모를 반환하도록 승격됩니다. 예를 들어, 다음 쿼리에서 T1.REVENUE가 DECIMAL(10,2) 열이고 T2.REVENUE가 DECIMAL(8,4) 열인 경우 10진수 결과는 DECIMAL(12,4)로 승격됩니다.

  ```
  select t1.revenue union select t2.revenue;
  ```

  규모는 두 열의 최대 규모인 `4`입니다. T1.REVENUE는 소수점 왼쪽에 8자리가 필요하므로(12 - 4 = 8) 정밀도는 `12`입니다. 이러한 유형 승격은 UNION 양쪽 모두의 값이 전부 결과에 부합하도록 합니다. 64비트 값의 경우, 최대 결과 정밀도는 19이고 최대 결과 규모는 18입니다. 128비트 값의 경우, 최대 결과 정밀도는 38이고 최대 결과 규모는 37입니다.

  결과 데이터 형식이 Amazon Redshift 전체 자릿수 및 소수 자릿수 제한을 초과하는 경우 쿼리는 오류를 반환합니다.
+ 설정 작업의 경우, 각각 상응하는 열 쌍에 대해 두 데이터 값이 *equal* 또는 *both NULL*인 경우 두 행이 동일한 것으로 처리됩니다. 예를 들어, 테이블 T1과 T2에 모두 한 열과 한 행이 있고 그 행이 두 테이블에서 모두 NULL인 경우 두 테이블에 대해 INTERSECT 연산을 수행하면 바로 그 행이 반환됩니다.

# UNION 쿼리 예
<a name="c_example_union_query"></a>

다음 UNION 쿼리에서 SALES 테이블의 행은 LISTING 테이블의 행과 병합됩니다. 각각의 테이블에서 호환되는 3개의 열이 선택되며, 이 경우에는 해당하는 열들의 이름과 데이터 형식이 동일합니다.

최종 결과 집합은 LISTING 테이블의 첫 번째 열을 기준으로 정렬되고 LISTID 값이 가장 높은 5개의 행으로 제한됩니다.

```
select listid, sellerid, eventid from listing
union select listid, sellerid, eventid from sales
order by listid, sellerid, eventid desc limit 5;

listid | sellerid | eventid
--------+----------+---------
1 |    36861 |    7872
2 |    16002 |    4806
3 |    21461 |    4256
4 |     8117 |    4337
5 |     1616 |    8647
(5 rows)
```

다음 예는 결과 집합에서 어떤 쿼리 표현식이 각각의 행을 생성했는지 볼 수 있도록 UNION 쿼리의 출력에 리터럴 값을 추가할 수 있는 방법을 보여줍니다. 이 쿼리는 첫 번째 쿼리 표현식의 행을 "B"(buyer)로 식별하고 두 번째 쿼리 표현식의 행을 "S"(seller)로 식별합니다.

이 쿼리는 \$110,000 이상의 티켓 거래에 대해 구매자와 판매자를 식별합니다. UNION 연산자의 어느 한쪽에서 두 쿼리 표현식의 유일한 차이점은 SALES 테이블에 대한 조인 열입니다.

```
select listid, lastname, firstname, username,
pricepaid as price, 'S' as buyorsell
from sales, users
where sales.sellerid=users.userid
and pricepaid >=10000
union
select listid, lastname, firstname, username, pricepaid,
'B' as buyorsell
from sales, users
where sales.buyerid=users.userid
and pricepaid >=10000
order by 1, 2, 3, 4, 5;

listid | lastname | firstname | username |   price   | buyorsell
--------+----------+-----------+----------+-----------+-----------
209658 | Lamb     | Colette   | VOR15LYI |  10000.00 | B
209658 | West     | Kato      | ELU81XAA |  10000.00 | S
212395 | Greer    | Harlan    | GXO71KOC |  12624.00 | S
212395 | Perry    | Cora      | YWR73YNZ |  12624.00 | B
215156 | Banks    | Patrick   | ZNQ69CLT |  10000.00 | S
215156 | Hayden   | Malachi   | BBG56AKU |  10000.00 | B
(6 rows)
```

중복된 행이 발견되는 경우 결과에 이런 행을 유지해야 하므로, 다음 예에서는 UNION ALL 연산자를 사용합니다. 이벤트 ID의 특정 시리즈에 대해, 쿼리는 각 이벤트와 관련된 각각의 판매에 대해 0개 이상의 행을 반환하고 그 이벤트의 각 목록에 대해 0개 또는 1개의 행을 반환합니다. 이벤트 ID는 LISTING 및 EVENT 테이블에서 각각의 행에 고유하지만, SALES 테이블에서 이벤트 및 목록 ID의 동일한 조합에 대해 여러 개의 판매 건이 있을 수 있습니다.

결과 집합의 세 번째 열은 행의 원본을 식별합니다. 행의 출처가 SALES 테이블인 경우 SALESROW 열에 "YES"로 표시됩니다. (SALESROW는 SALES.LISTID의 별칭입니다.) 행의 출처가 LISTING 테이블인 경우 SALESROW 열에 "No"로 표시됩니다.

이 경우, 결과 집합은 목록 500, 이벤트 7787에 대해 3개의 판매 행으로 구성됩니다. 즉, 이 목록 및 이벤트 조합에 대해 3가지 다른 트랜잭션이 발생했습니다. 다른 두 목록 501 및 502에서는 어떤 판매도 생성되지 않았으므로, 쿼리가 이들 목록 ID에 대해 생성하는 유일한 행의 출처는 LISTING 테이블입니다(SALESROW = 'No').

```
select eventid, listid, 'Yes' as salesrow
from sales
where listid in(500,501,502)
union all
select eventid, listid, 'No'
from listing
where listid in(500,501,502)
order by listid asc;

eventid | listid | salesrow
---------+--------+----------
7787 |    500 | No
7787 |    500 | Yes
7787 |    500 | Yes
7787 |    500 | Yes
6473 |    501 | No
5108 |    502 | No
(6 rows)
```

ALL 키워드 없이 같은 쿼리를 실행하는 경우 결과에는 판매 거래 중 하나만 유지됩니다.

```
select eventid, listid, 'Yes' as salesrow
from sales
where listid in(500,501,502)
union
select eventid, listid, 'No'
from listing
where listid in(500,501,502)
order by listid asc;

eventid | listid | salesrow
---------+--------+----------
7787 |    500 | No
7787 |    500 | Yes
6473 |    501 | No
5108 |    502 | No
(4 rows)
```

# UNION ALL 쿼리 예
<a name="c_example_unionall_query"></a>

중복된 행이 발견되는 경우 결과에 이런 행을 유지해야 하므로, 다음 예에서는 UNION ALL 연산자를 사용합니다. 이벤트 ID의 특정 시리즈에 대해, 쿼리는 각 이벤트와 관련된 각각의 판매에 대해 0개 이상의 행을 반환하고 그 이벤트의 각 목록에 대해 0개 또는 1개의 행을 반환합니다. 이벤트 ID는 LISTING 및 EVENT 테이블에서 각각의 행에 고유하지만, SALES 테이블에서 이벤트 및 목록 ID의 동일한 조합에 대해 여러 개의 판매 건이 있을 수 있습니다.

결과 집합의 세 번째 열은 행의 원본을 식별합니다. 행의 출처가 SALES 테이블인 경우 SALESROW 열에 "YES"로 표시됩니다. (SALESROW는 SALES.LISTID의 별칭입니다.) 행의 출처가 LISTING 테이블인 경우 SALESROW 열에 "No"로 표시됩니다.

이 경우, 결과 집합은 목록 500, 이벤트 7787에 대해 3개의 판매 행으로 구성됩니다. 즉, 이 목록 및 이벤트 조합에 대해 3가지 다른 트랜잭션이 발생했습니다. 다른 두 목록 501 및 502에서는 어떤 판매도 생성되지 않았으므로, 쿼리가 이들 목록 ID에 대해 생성하는 유일한 행의 출처는 LISTING 테이블입니다(SALESROW = 'No').

```
select eventid, listid, 'Yes' as salesrow
from sales
where listid in(500,501,502)
union all
select eventid, listid, 'No'
from listing
where listid in(500,501,502)
order by listid asc;

eventid | listid | salesrow
---------+--------+----------
7787 |    500 | No
7787 |    500 | Yes
7787 |    500 | Yes
7787 |    500 | Yes
6473 |    501 | No
5108 |    502 | No
(6 rows)
```

ALL 키워드 없이 같은 쿼리를 실행하는 경우 결과에는 판매 거래 중 하나만 유지됩니다.

```
select eventid, listid, 'Yes' as salesrow
from sales
where listid in(500,501,502)
union
select eventid, listid, 'No'
from listing
where listid in(500,501,502)
order by listid asc;

eventid | listid | salesrow
---------+--------+----------
7787 |    500 | No
7787 |    500 | Yes
6473 |    501 | No
5108 |    502 | No
(4 rows)
```

# INTERSECT 쿼리 예
<a name="c_example_intersect_query"></a>

다음 예를 첫 번째 UNION 예와 비교해 보십시오. 두 예에서는 사용되는 설정 연산자만 다를 뿐이지만, 그 결과는 매우 상이합니다. 다음과 같이 행들 중 하나만 같습니다.

```
235494 |    23875 |    8771
```

 이 행이 양쪽 테이블에서 발견된 5개 행의 제한된 결과에 있는 유일한 행입니다.

```
select listid, sellerid, eventid from listing
intersect
select listid, sellerid, eventid from sales
order by listid desc, sellerid, eventid
limit 5;

listid | sellerid | eventid
--------+----------+---------
235494 |    23875 |    8771
235482 |     1067 |    2667
235479 |     1589 |    7303
235476 |    15550 |     793
235475 |    22306 |    7848
(5 rows)
```

다음 쿼리는 3월에 뉴욕과 로스앤젤레스의 두 도시에서 모두 현장에서 이루어진 (티켓이 판매된) 이벤트를 찾습니다. 두 쿼리 표현식의 차이점은 VENUECITY 열에 대한 제약 조건입니다.

```
select distinct eventname from event, sales, venue
where event.eventid=sales.eventid and event.venueid=venue.venueid
and date_part(month,starttime)=3 and venuecity='Los Angeles'
intersect
select distinct eventname from event, sales, venue
where event.eventid=sales.eventid and event.venueid=venue.venueid
and date_part(month,starttime)=3 and venuecity='New York City'
order by eventname asc;

eventname
----------------------------
A Streetcar Named Desire
Dirty Dancing
Electra
Running with Annalise
Hairspray
Mary Poppins
November
Oliver!
Return To Forever
Rhinoceros
South Pacific
The 39 Steps
The Bacchae
The Caucasian Chalk Circle
The Country Girl
Wicked
Woyzeck
(16 rows)
```

# EXCEPT 쿼리 예
<a name="c_Example_MINUS_query"></a>

TICKIT 데이터베이스의 CATEGORY 테이블은 다음 11개의 행을 포함합니다.

```
 catid | catgroup |  catname  |                  catdesc
-------+----------+-----------+--------------------------------------------
   1   | Sports   | MLB       | Major League Baseball
   2   | Sports   | NHL       | National Hockey League
   3   | Sports   | NFL       | National Football League
   4   | Sports   | NBA       | National Basketball Association
   5   | Sports   | MLS       | Major League Soccer
   6   | Shows    | Musicals  | Musical theatre
   7   | Shows    | Plays     | All non-musical theatre
   8   | Shows    | Opera     | All opera and light opera
   9   | Concerts | Pop       | All rock and pop music concerts
  10   | Concerts | Jazz      | All jazz singers and bands
  11   | Concerts | Classical | All symphony, concerto, and choir concerts
(11 rows)
```

CATEGORY\$1STAGE 테이블(스테이징 테이블)에 추가적인 행이 한 개 있다고 가정합니다.

```
 catid | catgroup |  catname  |                  catdesc
-------+----------+-----------+--------------------------------------------
1 | Sports   | MLB       | Major League Baseball
2 | Sports   | NHL       | National Hockey League
3 | Sports   | NFL       | National Football League
4 | Sports   | NBA       | National Basketball Association
5 | Sports   | MLS       | Major League Soccer
6 | Shows    | Musicals  | Musical theatre
7 | Shows    | Plays     | All non-musical theatre
8 | Shows    | Opera     | All opera and light opera
9 | Concerts | Pop       | All rock and pop music concerts
10 | Concerts | Jazz      | All jazz singers and bands
11 | Concerts | Classical | All symphony, concerto, and choir concerts
12 | Concerts | Comedy    | All stand up comedy performances
(12 rows)
```

두 테이블 사이의 차이점을 반환합니다. 다시 말해, CATEGORY\$1STAGE 테이블에는 있지만 CATEGORY 테이블에는 없는 행을 반환합니다.

```
select * from category_stage
except
select * from category;

catid | catgroup | catname |             catdesc
-------+----------+---------+----------------------------------
12 | Concerts | Comedy  | All stand up comedy performances
(1 row)
```

다음과 같은 동등한 쿼리는 동의어 MINUS를 사용합니다.

```
select * from category_stage
minus
select * from category;

catid | catgroup | catname |             catdesc
-------+----------+---------+----------------------------------
12 | Concerts | Comedy  | All stand up comedy performances
(1 row)
```

SELECT 표현식의 순서를 반대로 하면 쿼리가 아무런 행도 반환하지 않습니다.

# ORDER BY 절
<a name="r_ORDER_BY_clause"></a>

**Topics**
+ [구문](#r_ORDER_BY_clause-synopsis)
+ [파라미터](#r_ORDER_BY_clause-parameters)
+ [사용 노트](#r_ORDER_BY_usage_notes)
+ [ORDER BY 사용 예](r_Examples_with_ORDER_BY.md)

ORDER BY 절은 쿼리의 결과 집합을 정렬합니다.

## 구문
<a name="r_ORDER_BY_clause-synopsis"></a>

```
[ ORDER BY expression [ ASC | DESC ] ]
[ NULLS FIRST | NULLS LAST ]
[ LIMIT { count | ALL } ]
[ OFFSET start ]
```

## 파라미터
<a name="r_ORDER_BY_clause-parameters"></a>

 * expression*   
일반적으로 선택 목록에 하나 이상의 열을 지정하여 쿼리 결과 집합의 정렬 순서를 정의하는 표현식입니다. 결과는 이진 UTF-8 순서를 기준으로 반환됩니다. 다음을 지정할 수도 있습니다.  
+ 선택 목록에 없는 열
+ 쿼리에서 참조하는 테이블에 존재하는 하나 이상의 열에서 형성되는 표현식
+ 선택 목록 항목의 위치(또는 선택 목록이 없는 경우 테이블에서 열의 위치)를 나타내는 서수
+ 선택 목록 항목을 정의하는 별칭
ORDER BY 절에 여러 개의 표현식이 포함되어 있을 때는 결과 집합이 첫 번째 표현식에 따라 정렬된 다음, 두 번째 표현식이 첫 번째 표현식의 일치하는 값을 가진 행에 적용되는 등의 방식이 적용됩니다.

ASC \$1 DESC   
표현식의 정렬 순서를 정의하는 옵션으로서 각각 다음과 같은 의미를 갖습니다.  
+ ASC: 오름차순(예: 숫자 값의 경우 낮은 값에서 높은 값 순, 문자열의 경우 'A'에서 'Z'의 순. 지정된 옵션이 없는 경우에는 데이터가 기본적으로 오름차순으로 정렬됩니다.
+ DESC: 내림차순(숫자 값의 경우 높은 값에서 낮은 값 순, 문자열의 경우 'Z'에서 'A'의 순).

NULLS FIRST \$1 NULLS LAST  
NULL 값의 순서를 NULL 값 이외의 값 이전에 결정할지, 혹은 이후에 결정할지 지정하는 옵션입니다. 기본적으로 NULL 값은 ASC 순서에서는 마지막에 정렬 후 순위가 결정되며, DESC 순서에서는 처음에 정렬 후 순위가 결정됩니다.

LIMIT *number* \$1 ALL   <a name="order-by-clause-limit"></a>
쿼리가 반환하는 정렬된 행의 수를 제어하는 옵션입니다. LIMIT 수는 양의 정수여야 합니다. 최댓값은 `2147483647`입니다.  
LIMIT 0은 아무런 행도 반환하지 않습니다. 이 구문을 테스트 목적으로 사용할 수 있습니다. 즉, 쿼리가 실행되는지 확인하거나(어떤 행도 표시하지 않음) 테이블에서 열 목록을 반환합니다. LIMIT 0을 사용하여 열 목록을 반환하는 경우 ORDER BY 절은 중복입니다. 기본값은 LIMIT ALL입니다.

OFFSET *start*   <a name="order-by-clause-offset"></a>
행 반환을 위해 시작하기 전에 *start* 앞에 있는 행의 개수를 건너뛰도록 지정하는 옵션입니다. OFFSET 수는 양의 정수여야 합니다. 최댓값은 `2147483647`입니다. LIMIT 옵션과 함께 사용 시, OFFSET개의 행을 건너뛴 후 반환되는 LIMIT 행 수를 카운트하기 시작합니다. LIMIT 옵션이 사용되지 않는 경우 결과 집합의 행 개수는 건너뛰는 행 개수만큼 감소됩니다. OFFSET 절에 의해 건너뛰는 행을 계속 스캔해야 하므로, 큰 OFFSET 값을 사용하기에 부족할 수 있습니다.

## 사용 노트
<a name="r_ORDER_BY_usage_notes"></a>

 ORDER BY 절을 사용할 때 다음과 같이 예상되는 동작에 유의하세요.
+ NULL 값은 다른 모든 값보다 "높은 값"으로 간주됩니다. 기본 오름차순 정렬 순서에 따라 NULL 값은 끝에 정렬됩니다. 이 동작을 변경하려면 NULLS FIRST 옵션을 사용하세요.
+ 쿼리에 ORDER BY 절이 포함되어 있지 않을 때, 시스템에서는 행 순서를 예측할 수 없는 결과 집합을 반환합니다. 같은 쿼리를 두 번 실행할 경우 결과 집합을 다른 순서로 반환할 수도 있습니다.
+ ORDER BY 절 없이 LIMIT 및 OFFSET 옵션을 사용할 수 있지만, 일관성 있는 행 집합을 반환하려면 ORDER BY와 함께 이러한 옵션을 사용하세요.
+ Amazon Redshift와 같은 병렬 시스템에서는 ORDER BY가 고유한 순서를 지정하지 않으면 행의 순서는 비확정적입니다. 다시 말해 ORDER BY 표현식에서 중복 값이 산출되면 해당하는 행의 반환 순서가 다른 시스템과는 다르거나 Amazon Redshift를 실행할 때마다 달라질 수 있습니다.
+ Amazon Redshift는 ORDER BY 절에서 문자열 리터럴을 지원하지 않습니다.

# ORDER BY 사용 예
<a name="r_Examples_with_ORDER_BY"></a>

두 번째 열인 CATGROUP 열을 기준으로 정렬된 CATEGORY 테이블에서 11개의 행을 전부 반환합니다. 같은 CATGROUP 값을 가진 결과에 대해서는 문자열의 길이를 기준으로 CATDESC 열 값의 순서를 지정합니다. 그런 다음 열 CATID 및 CATNAME을 기준으로 정렬합니다.

```
select * from category order by 2, length(catdesc), 1, 3;

catid | catgroup |  catname  |                  catdesc
------+----------+-----------+----------------------------------------
10    | Concerts | Jazz      | All jazz singers and bands
9     | Concerts | Pop       | All rock and pop music concerts
11    | Concerts | Classical | All symphony, concerto, and choir conce
6     | Shows    | Musicals  | Musical theatre
7     | Shows    | Plays     | All non-musical theatre
8     | Shows    | Opera     | All opera and light opera
5     | Sports   | MLS       | Major League Soccer
1     | Sports   | MLB       | Major League Baseball
2     | Sports   | NHL       | National Hockey League
3     | Sports   | NFL       | National Football League
4     | Sports   | NBA       | National Basketball Association
(11 rows)
```

가장 높은 QTYSOLD 값을 기준으로 정렬된 SALES 테이블에서 선택한 열을 반환합니다. 결과를 맨 위의 10개 행으로 제한합니다.

```
select salesid, qtysold, pricepaid, commission, saletime from sales
order by qtysold, pricepaid, commission, salesid, saletime desc
limit 10;

salesid | qtysold | pricepaid | commission |      saletime
--------+---------+-----------+------------+---------------------
15401   |       8 |    272.00 |      40.80 | 2008-03-18 06:54:56
61683   |       8 |    296.00 |      44.40 | 2008-11-26 04:00:23
90528   |       8 |    328.00 |      49.20 | 2008-06-11 02:38:09
74549   |       8 |    336.00 |      50.40 | 2008-01-19 12:01:21
130232  |       8 |    352.00 |      52.80 | 2008-05-02 05:52:31
55243   |       8 |    384.00 |      57.60 | 2008-07-12 02:19:53
16004   |       8 |    440.00 |      66.00 | 2008-11-04 07:22:31
489     |       8 |    496.00 |      74.40 | 2008-08-03 05:48:55
4197    |       8 |    512.00 |      76.80 | 2008-03-23 11:35:33
16929   |       8 |    568.00 |      85.20 | 2008-12-19 02:59:33
(10 rows)
```

LIMIT 0 구문을 사용하여 열 목록은 반환하고 행은 반환하지 않습니다.

```
select * from venue limit 0;
venueid | venuename | venuecity | venuestate | venueseats
---------+-----------+-----------+------------+------------
(0 rows)
```

# CONNECT BY 절
<a name="r_CONNECT_BY_clause"></a>

계층 구조에서 행 간의 관계를 지정합니다. CONNECT BY를 사용하여 테이블을 자체에 조인하고 계층적 데이터를 처리하여 계층적 순서로 행을 선택할 수 있습니다. 예를 들어 조직도와 목록 데이터를 반복적으로 반복하는 데 사용할 수 있습니다.

계층적 쿼리는 다음 순서로 처리됩니다.

1. FROM 절에 조인이 있는 경우 조인이 먼저 처리됩니다.

1. CONNECT BY 절이 평가됩니다.

1. WHERE 절이 평가됩니다.

## 구문
<a name="r_CONNECT_BY_clause-synopsis"></a>

```
[START WITH start_with_conditions]
CONNECT BY connect_by_conditions
```

**참고**  
START 및 CONNECT는 예약어가 아니지만, 쿼리에서 START 및 CONNECT를 테이블 별칭으로 사용하는 경우에는 런타임 시 오류가 발생하지 않도록 구분된 식별자(큰따옴표) 또는 AS를 사용하세요.

```
SELECT COUNT(*)
FROM Employee "start"
CONNECT BY PRIOR id = manager_id
START WITH name = 'John'
```

```
SELECT COUNT(*)
FROM Employee AS start
CONNECT BY PRIOR id = manager_id
START WITH name = 'John'
```

## 파라미터
<a name="r_CONNECT_BY_parameters"></a>

 *start\$1with\$1conditions*   
계층 구조의 루트 행을 지정하는 조건

 *connect\$1by\$1conditions*   
계층 구조의 상위 행과 하위 행 간의 관계를 지정하는 조건입니다. 하나 이상의 조건이 부모 행을 참조하는 데 사용되는 ` ` 단항 연산자로 한정되어야 합니다.  

```
PRIOR column = expression
-- or
expression > PRIOR column
```

## 연산자
<a name="r_CONNECT_BY_operators"></a>

CONNECT BY 쿼리에서 다음 연산자를 사용할 수 있습니다.

 *LEVEL*   
계층 구조에서 현재 행 수준을 반환하는 의사 열입니다. 루트 행에 대해 1, 루트 행의 자식에 대해 2 등을 반환합니다.

 *PRIOR*   
계층 구조에서 현재 행의 상위 행에 대한 표현식을 평가하는 단항 연산자입니다.

## 예제
<a name="r_CONNECT_BY_example"></a>

다음 예는 John에게 직간접적으로 보고하는 직원 수를 반환하는 CONNECT BY 쿼리입니다(4단계 미만).

```
SELECT id, name, manager_id
FROM employee
WHERE LEVEL < 4
START WITH name = 'John'
CONNECT BY PRIOR id = manager_id;
```

다음은 쿼리 결과입니다.

```
id      name      manager_id
------+----------+--------------
  101     John        100
  102     Jorge       101
  103     Kwaku       101
  110     Liu         101
  201     Sofía       102
  106     Mateo       102
  110     Nikki       103
  104     Paulo       103
  105     Richard     103
  120     Saanvi      104
  200     Shirley     104
  205     Zhang       104
```

 이 예에 대한 테이블 정의는 다음과 같습니다.

```
CREATE TABLE employee (
   id INT,
   name VARCHAR(20),
   manager_id INT
   );
```

 다음은 테이블에 삽입된 행입니다.

```
INSERT INTO employee(id, name, manager_id)  VALUES
(100, 'Carlos', null),
(101, 'John', 100),
(102, 'Jorge', 101),
(103, 'Kwaku', 101),
(110, 'Liu', 101),
(106, 'Mateo', 102),
(110, 'Nikki', 103),
(104, 'Paulo', 103),
(105, 'Richard', 103),
(120, 'Saanvi', 104),
(200, 'Shirley', 104),
(201, 'Sofía', 102),
(205, 'Zhang', 104);
```

다음은 John의 부서의 조직도입니다.

![\[John의 부서의 조직도 다이어그램.\]](http://docs.aws.amazon.com/ko_kr/redshift/latest/dg/images/org-chart.png)


# 하위 쿼리 예
<a name="r_Subquery_examples"></a>

다음 예에서는 하위 쿼리가 SELECT 쿼리에 적합한 다른 방법을 보여줍니다. 하위 쿼리의 다른 사용 예는 [JOIN 예](r_Join_examples.md) 섹션을 참조하세요.

## SELECT 목록 하위 쿼리
<a name="r_Subquery_examples-select-list-subquery"></a>

다음 예에서는 SELECT 목록에 하위 쿼리를 포함합니다. 이 하위 쿼리는 *스칼라*이므로 한 개의 열과 한 개의 값만 반환하며, 이는 외부 쿼리에서 반환되는 각 행에 대한 결과에서 반복됩니다. 이 쿼리는 외부 쿼리에 의해 정의된 바와 같이 2008년의 다른 두 분기(2분기 및 3분기)에 대한 판매액 값과 하위 쿼리가 계산하는 Q1SALES 값을 비교합니다.

```
select qtr, sum(pricepaid) as qtrsales,
(select sum(pricepaid)
from sales join date on sales.dateid=date.dateid
where qtr='1' and year=2008) as q1sales
from sales join date on sales.dateid=date.dateid
where qtr in('2','3') and year=2008
group by qtr
order by qtr;

qtr  |  qtrsales   |   q1sales
-------+-------------+-------------
2     | 30560050.00 | 24742065.00
3     | 31170237.00 | 24742065.00
(2 rows)
```

## WHERE 절 하위 쿼리
<a name="r_Subquery_examples-where-clause-subquery"></a>

다음 예에서는 WHERE 절에 테이블 하위 쿼리를 포함합니다. 이 하위 쿼리는 여러 개의 행을 만들어냅니다. 이 경우에는 행에 한 개의 열만 포함되지만, 테이블 하위 쿼리는 다른 테이블과 마찬가지로 여러 개의 열과 행을 포함할 수 있습니다.

이 쿼리는 최대 판매 티켓 수를 기준으로 상위 10개의 판매사를 찾습니다. 톱 10 목록은 티켓 판매소가 있는 도시에 사는 사용자를 제거하는 하위 쿼리에 의해 한정됩니다. 이 쿼리는 다양한 방법으로 작성할 수 있습니다. 예를 들어, 하위 쿼리를 기본 쿼리 내의 조인으로 다시 작성할 수 있습니다.

```
select firstname, lastname, city, max(qtysold) as maxsold
from users join sales on users.userid=sales.sellerid
where users.city not in(select venuecity from venue)
group by firstname, lastname, city
order by maxsold desc, city desc
limit 10;

firstname | lastname  |      city      | maxsold
-----------+-----------+----------------+---------
Noah       | Guerrero | Worcester      |       8
Isadora    | Moss     | Winooski       |       8
Kieran     | Harrison | Westminster    |       8
Heidi      | Davis    | Warwick        |       8
Sara       | Anthony  | Waco           |       8
Bree       | Buck     | Valdez         |       8
Evangeline | Sampson  | Trenton        |       8
Kendall    | Keith    | Stillwater     |       8
Bertha     | Bishop   | Stevens Point  |       8
Patricia   | Anderson | South Portland |       8
(10 rows)
```

## WITH 절 하위 쿼리
<a name="r_Subquery_examples-with-clause-subqueries"></a>

[WITH 절](r_WITH_clause.md)을(를) 참조하세요.

# 상관관계가 있는 하위 쿼리
<a name="r_correlated_subqueries"></a>

다음 예에서는 WHERE 절에 *상관관계가 있는 하위 쿼리*가 포함됩니다. 이런 종류의 하위 쿼리는 자신의 열과 외부 쿼리에 의해 생성되는 열 사이에 하나 이상의 상관관계를 포함합니다. 이 경우 상관관계는 `where s.listid=l.listid`입니다. 외부 쿼리가 생성하는 각각의 행에 자격을 주거나 자격을 취소하는 하위 쿼리가 실행됩니다.

```
select salesid, listid, sum(pricepaid) from sales s
where qtysold=
(select max(numtickets) from listing l
where s.listid=l.listid)
group by 1,2
order by 1,2
limit 5;

salesid | listid |   sum
--------+--------+----------
 27     |     28 | 111.00
 81     |    103 | 181.00
 142    |    149 | 240.00
 146    |    152 | 231.00
 194    |    210 | 144.00
(5 rows)
```

## 지원되지 않는 상관관계를 가진 하위 쿼리 패턴
<a name="r_correlated_subqueries-correlated-subquery-patterns-that-are-not-supported"></a>

쿼리 플래너는 하위 쿼리 상관관계 제거라는 쿼리 재작성 방법을 사용하여 MPP 환경에서 실행하기 위해 상관관계가 있는 하위 쿼리의 여러 패턴을 최적화합니다. 상관관계를 가진 몇 가지 유형의 하위 쿼리는 Amazon Redshift가 상관관계를 제거할 수 없고 지원하지 않는 패턴을 따릅니다. 다음 상관관계 참조를 포함하는 쿼리는 오류를 반환합니다.
+  "건너뛰기 수준의 상관관계 참조"라고도 하는, 쿼리 블록을 건너뛰는 상관관계 참조. 예를 들어, 다음 쿼리에서 상관관계 참조를 포함하는 블록과 건너뛰는 블록은 NOT EXISTS 조건자에 의해 연결됩니다.

  ```
  select event.eventname from event
  where not exists
  (select * from listing
  where not exists
  (select * from sales where event.eventid=sales.eventid));
  ```

  이 경우에 건너뛰는 블록은 LISTING 테이블에 대한 하위 쿼리입니다. 상관관계 참조는 EVENT 테이블과 SALES 테이블의 상관관계를 지정합니다.
+  외부 조인에서 ON 절의 일부인 하위 쿼리에서의 상관관계 참조: 

  ```
  select * from category
  left join event
  on category.catid=event.catid and eventid =
  (select max(eventid) from sales where sales.eventid=event.eventid);
  ```

  ON 절은 외부 쿼리의 EVENT에 대한 하위 쿼리에 있는 SALES에서의 상관관계 참조를 포함합니다.
+ Amazon Redshift 시스템 테이블에 대해 Null에 민감한 상관관계 참조. 예: 

  ```
  select attrelid
  from stv_locks sl, pg_attribute
  where sl.table_id=pg_attribute.attrelid and 1 not in
  (select 1 from pg_opclass where sl.lock_owner = opcowner);
  ```
+ 창 함수를 포함하는 하위 쿼리 내에서의 상관관계 참조.

  ```
  select listid, qtysold
  from sales s
  where qtysold not in
  (select sum(numtickets) over() from listing l where s.listid=l.listid);
  ```
+ GROUP BY 열에서 상관관계를 가진 하위 쿼리의 결과에 대한 참조. 예: 

  ```
  select listing.listid,
  (select count (sales.listid) from sales where sales.listid=listing.listid) as list
  from listing
  group by list, listing.listid;
  ```
+ IN 조건자에 의해 외부 쿼리에 연결된 집계 함수와 GROUP BY 절이 있는 하위 쿼리에서의 상관관계 참조. (이 제한 사항은 MIN 및 MAX 집계 함수에는 적용되지 않습니다.) 예제: 

  ```
  select * from listing where listid in
  (select sum(qtysold)
  from sales
  where numtickets>4
  group by salesid);
  ```