> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> 파이프 연산자 문서

# 파이프 연산자

파이프 연산자를 사용하면 [GoogleSQL의 파이프 구문](https://research.google/pubs/sql-has-problems-we-can-fix-them-pipe-syntax-in-sql/)처럼 위에서 아래로 읽을 수 있는 선형 변환 체인 형태로 쿼리를 작성할 수 있습니다.

```sql theme={null}
FROM orders
|> WHERE cancelled = 0
|> AGGREGATE sum(amount) AS total GROUP BY customer
|> ORDER BY total DESC
|> LIMIT 3
```

모든 `SELECT` 쿼리 뒤에 파이프 연산자 체인을 추가할 수 있습니다. 각 연산자는 `|>` 토큰으로 시작하고, 앞선 쿼리의 결과를 입력으로 받아 변환을 하나 더 적용합니다. 각 연산자 내부에서는 일반 ClickHouse 구문을 사용합니다.

파이프 연산자는 구문 확장 기능입니다. 각 연산자는 앞선 쿼리를 서브쿼리로 감싸므로, 결과 AST는 중첩된 서브쿼리로 작성한 동등한 쿼리의 AST와 같습니다. 따라서 위 쿼리는 다음과 동일합니다.

```sql theme={null}
SELECT * FROM
(
    SELECT customer, sum(amount) AS total FROM
    (
        SELECT * FROM
        (
            SELECT * FROM orders
        )
        WHERE cancelled = 0
    )
    GROUP BY customer
)
ORDER BY total DESC
LIMIT 3
```

<div id="from-queries">
  ## FROM 쿼리
</div>

쿼리는 `FROM` 절로 시작할 수 있으며, 이러한 쿼리에서는 `SELECT` 절을 선택적으로 지정할 수 있습니다. `SELECT` 절을 생략하면 `SELECT *`를 작성한 것처럼 동작합니다:

```sql theme={null}
FROM orders;
FROM orders WHERE amount > 100;
FROM orders |> WHERE amount > 100;
```

테이블 별칭은 일반 `SELECT` 쿼리의 `FROM` 절처럼 `AS` 키워드의 사용 여부와 관계없이 작성할 수 있습니다: `FROM orders o WHERE o.amount > 100`. 유일한 예외는 별칭으로 `select`라는 단어만 단독으로 사용하는 경우입니다. 테이블 뒤에 `select`가 오면 별칭이 아니라 명시적 `SELECT` 절의 시작으로 해석됩니다. 이름이 `select`인 테이블에는 영향을 주지 않으며, 자체 별칭을 그대로 사용할 수 있습니다: `FROM select s WHERE s.id = 1`.

마지막 테이블의 샘플 오프셋을 쿼리 수준 `OFFSET`으로도 해석할 수 있는 경우에는 `SELECT` 절을 생략할 수 없습니다. `FROM t SAMPLE 1/10 OFFSET 5`에서 `OFFSET`은 `SAMPLE`에 속하지만, `FROM t SAMPLE 1/10 SELECT * OFFSET 5`에서는 쿼리 수준 `OFFSET`이므로 둘을 구분하려면 명시적 `SELECT`가 필요합니다. 쿼리가 쿼리 수준 `OFFSET` 앞에 올 수 없는 절로 이어지는 경우에는 모호하지 않으므로, 평소처럼 `SELECT` 절은 선택 사항입니다: `FROM t SAMPLE 1/10 OFFSET 5 WHERE x > 0`, `FROM t SAMPLE 1/10 OFFSET 5 JOIN dim USING (id)`.

<div id="operators">
  ## 연산자
</div>

<div id="where">
  ### WHERE
</div>

`|> WHERE condition`은 입력 행을 필터링합니다. 집계 뒤에 적용하면 `HAVING`처럼 작동합니다:

```sql theme={null}
FROM orders
|> AGGREGATE sum(amount) AS total GROUP BY customer
|> WHERE total > 100
```

<div id="select">
  ### SELECT
</div>

`|> SELECT [DISTINCT] expr1 [AS alias1], ...`는 나열된 표현식만 출력 컬럼으로 유지합니다:

```sql theme={null}
FROM orders |> SELECT customer, amount * 2 AS doubled
```

표현식 목록 끝에는 일반 쿼리의 `SELECT` 절과 동일한 위치에 후행 쉼표를 사용할 수 있습니다. 이 경우 뒤에는 쿼리의 끝이나 다음 `|>` 연산자가 올 수 있습니다: `FROM orders |> SELECT customer, amount, |> LIMIT 1`. 이는 `EXTEND` 및 `AGGREGATE` 연산자에도 동일하게 적용됩니다.

<div id="extend">
  ### EXTEND
</div>

`|> EXTEND expr1 [AS alias1], ...`는 나열된 표현식을 입력 컬럼에 추가합니다. 이는 `SELECT *, expr1 AS alias1, ...`와 동일합니다:

```sql theme={null}
FROM orders |> EXTEND amount * 10 AS big
```

<div id="set">
  ### SET
</div>

`|> SET column1 = expr1, ...`는 나열된 컬럼의 값을 대체하며, `SELECT * REPLACE (expr1 AS column1, ...)`와 동일합니다:

```sql theme={null}
FROM orders |> SET amount = amount + 1000
```

<div id="drop">
  ### DROP
</div>

`|> DROP column1, ...`은 나열된 컬럼을 삭제합니다. 이는 `SELECT * EXCEPT (column1, ...)`와 동일합니다:

```sql theme={null}
FROM orders |> DROP cancelled
```

<div id="as">
  ### AS
</div>

`|> AS alias`는 다음 연산자의 입력에 별칭을 지정하여 해당 연산자에서 참조할 수 있게 하며, 주로 조인에 유용합니다:

```sql theme={null}
FROM orders
|> AGGREGATE sum(amount) AS total GROUP BY customer
|> AS agg
|> JOIN orders AS o ON agg.customer = o.customer
```

<div id="aggregate">
  ### AGGREGATE
</div>

`|> AGGREGATE agg1 [AS alias1], ... [GROUP BY expr1 [AS alias1], ...]`는 입력 행을 집계합니다. 출력 컬럼은 그룹화 컬럼 뒤에 집계 컬럼이 이어지는 순서로 구성됩니다. `GROUP BY`가 없으면 전체 입력을 단일 행으로 집계합니다:

```sql theme={null}
FROM orders |> AGGREGATE count() AS c, sum(amount) AS total GROUP BY customer;
FROM orders |> AGGREGATE count() AS c;
```

<div id="distinct">
  ### DISTINCT
</div>

`|> DISTINCT`는 중복된 행을 제거하며, `SELECT DISTINCT *`와 동일합니다.

<div id="order-by">
  ### ORDER BY
</div>

`|> ORDER BY expr1 [ASC/DESC], ...`는 입력 행을 정렬합니다. `ORDER BY ALL`, `WITH FILL`, `INTERPOLATE`를 포함하여 `ORDER BY` 절의 전체 구문을 지원합니다:

```sql theme={null}
FROM orders |> ORDER BY amount DESC;
FROM orders |> SELECT customer, amount |> ORDER BY ALL;
FROM points |> ORDER BY x WITH FILL FROM 1 TO 10 INTERPOLATE (y AS y + 1)
```

<div id="limit-and-offset">
  ### LIMIT 및 OFFSET
</div>

`|> LIMIT length [OFFSET offset]` 및 `|> OFFSET offset`는 반환되는 행 수를 제한합니다:

```sql theme={null}
FROM orders |> ORDER BY amount DESC |> LIMIT 3 OFFSET 1
```

<div id="join-and-array-join">
  ### JOIN 및 ARRAY JOIN
</div>

`|> [GLOBAL] [ANY/ALL/ASOF/SEMI/ANTI] [INNER/LEFT/RIGHT/FULL/CROSS] JOIN table [ON expr | USING (columns)]`는 입력을 다른 테이블, 서브쿼리 또는 테이블 함수와 조인합니다. 모든 유형의 [JOIN](/docs/ko/reference/statements/select/join) 및 [ARRAY JOIN](/docs/ko/reference/statements/select/array-join)이 지원되며, 하나의 연산자에 `FROM` 절처럼 여러 조인을 포함할 수 있습니다:

```sql theme={null}
FROM customers
|> AS c
|> LEFT JOIN orders AS o ON c.name = o.customer
|> ARRAY JOIN tags
```

각 연산자는 새로운 서브쿼리 범위를 형성하므로 테이블 별칭은 같은 연산자 내의 `ON` 조건에서만 사용할 수 있습니다. 이후 연산자에서는 `SELECT *` 뒤와 마찬가지로 조인 결과의 결합된 컬럼을 볼 수 있습니다.

연산자의 입력을 왼쪽 피연산자로 하는 크로스 조인의 쉼표 표기법도 지원합니다. `FROM customers |> AS c |> , orders` 다른 조인과 마찬가지로 `joined_subquery_requires_alias` 설정이 활성화된 경우(기본적으로 활성화됨) 입력에 별칭이 필요합니다.

일반 쿼리의 `FROM` 절과 마찬가지로 `ARRAY JOIN` 바로 뒤에서는 쉼표(크로스) 조인이 지원되지 않습니다. `ARRAY JOIN` 뒤의 쉼표는 항상 해당 표현식 목록에 속합니다.

<div id="union-intersect-and-except">
  ### UNION, INTERSECT 및 EXCEPT
</div>

`|> UNION [ALL/DISTINCT] (query1) [, (query2), ...]`, `|> INTERSECT [ALL/DISTINCT] ...`, `|> EXCEPT [ALL/DISTINCT] ...`는 입력을 다른 쿼리 결과와 결합합니다.

```sql theme={null}
FROM orders
|> SELECT customer
|> UNION ALL (FROM customers |> SELECT name)
|> DISTINCT
```

단일 쿼리에서는 피연산자 주위의 괄호를 생략할 수 있습니다. 하지만 집합 연산 뒤에 다른 파이프 연산자가 이어지는 경우에는 괄호가 필요합니다. 그렇지 않으면 다음 연산자가 마지막 피연산자에 적용되는지, 전체 결과에 적용되는지 알 수 없기 때문입니다.

<div id="notes">
  ## 참고
</div>

* 쿼리의 `WITH` 절은 스칼라 별칭과 CTE 모두에서 이후의 모든 파이프 연산자에 계속 적용됩니다. `WITH 10 AS threshold FROM t |> WHERE x < threshold`
* `INSERT ... SELECT`에서 `INSERT` 앞에 작성한 `WITH` 절은 생성된 가장 바깥쪽 `SELECT`에 연결되며, 수동으로 작성한 중첩 서브쿼리와 마찬가지로 `enable_global_with_statement` 설정(기본적으로 활성화됨)을 통해 해석 과정에서 내부 파이프 단계까지 적용됩니다. 이 설정이 비활성화되면 `INSERT` 범위의 `WITH`에 정의된 별칭과 CTE는 수동으로 작성한 서브쿼리 내부에서 보이지 않는 것과 마찬가지로 파이프 단계 내부에서도 보이지 않습니다.
* 다른 모든 `SELECT` 쿼리와 마찬가지로 파이프 연산자가 생성한 쿼리는 해당 생성 쿼리에 연결되는 `SETTINGS` 절로 끝날 수 있습니다. `FROM t |> LIMIT 1 SETTINGS max_threads = 1`은 `SELECT * FROM (SELECT * FROM t) LIMIT 1 SETTINGS max_threads = 1`과 같습니다. 이는 서브쿼리, `CREATE VIEW`, `view` 테이블 함수처럼 쿼리 설정을 별도로 처리하는 단계가 없는 경우에도 작동합니다. 체인 중간의 `SETTINGS` 절은 해당 단계에 유지되며, 이 단계는 다음 연산자의 서브쿼리가 됩니다. 괄호로 묶인 피연산자가 있는 집합 연산 뒤에는 후행 `SETTINGS`를 사용할 수 없습니다. 서브쿼리를 사용한 동등한 쿼리도 해당 위치에 `SETTINGS` 절을 사용할 수 없습니다.
* 첫 번째 파이프 연산자 앞의 쿼리에 있는 `SETTINGS` 절은 해당 쿼리에 유지되며, 이 쿼리는 생성된 래퍼의 서브쿼리가 됩니다. 일반 설정은 서브쿼리 해석 시 해당 서브쿼리의 설정이 적용되므로 계속 작동합니다. 유일한 예외는 쿼리 분석기를 선택하는 설정 쌍인 `enable_analyzer`와 그 별칭 `allow_experimental_analyzer`입니다. 서브쿼리에서 이 설정들을 변경할 수 없으므로 `SELECT number FROM numbers(1) SETTINGS enable_analyzer = 0 |> LIMIT 1`은 `INCORRECT_QUERY`를 발생시킵니다. 이는 수동으로 작성한 동등한 쿼리인 `SELECT * FROM (SELECT number FROM numbers(1) SETTINGS enable_analyzer = 0) LIMIT 1`도 마찬가지입니다. 이 두 설정은 마지막 파이프 연산자 뒤에 작성하거나 쿼리 외부에서 전달하십시오.
* 파이프 연산자는 집합 연산을 포함해 앞에 있는 전체 쿼리에 결합됩니다. `SELECT 1 UNION ALL SELECT 2 |> AGGREGATE count()`에서는 집계가 `UNION ALL`의 결과에 적용됩니다. 파이프 연산자 뒤에 `UNION`으로 쿼리를 이어가려면 `|> UNION` 연산자 또는 괄호를 사용하십시오.
* 파이프 연산자는 서브쿼리, `INSERT ... SELECT`(`INSERT INTO t FROM src |> ...` 형식 포함), `CREATE VIEW`, `view` 테이블 함수 등 `SELECT` 쿼리가 필요한 모든 곳에서 사용할 수 있습니다.
* 컬럼 이름을 제자리에서 변경하는 별도 연산자는 제공되지 않습니다. `|> SELECT * EXCEPT (old_name), old_name AS new_name` 또는 `SET` 및 `DROP` 연산자를 사용하십시오.
