개요
설명
윈도우 함수(분석 함수라고도 함)는 원래 행을 유지하면서 계산을 수행하는 특수 내장 함수입니다. 집계 함수와 달리 윈도우 함수는 다음과 같은 특징이 있습니다.
- GROUP BY로 그룹화하는 대신 특정 윈도우 범위 내의 데이터를 처리합니다.
- 결과 집합의 각 행에 대해 값을 계산합니다.
- SELECT 목록에 열을 추가할 수 있습니다.
- 쿼리 처리의 마지막 단계(JOIN, WHERE, GROUP BY 이후)에 실행됩니다.
윈도우 함수는 재무 및 과학 계산에서 추세 분석, 이상값 계산, 데이터 버킷화에 흔히 사용됩니다.
구문
<FUNCTION> ( [ <ARGUMENTS> ] ) OVER ( [ <windowDefinition> ] )
각 구성 요소는 다음과 같이 정의됩니다.
windowDefinition ::=
[ PARTITION BY <expr1> [, ...] ]
[ ORDER BY <expr2> [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ <windowFrameClause> ]
windowFrameClause ::=
{
| { ROWS } <n> PRECEDING
| { ROWS } CURRENT ROW
| { ROWS } BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
| { ROWS | RANGE } UNBOUNDED PRECEDING
| { ROWS | RANGE } BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
| { ROWS | RANGE } BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
| { ROWS } BETWEEN <n> { PRECEDING | FOLLOWING } AND <n> { PRECEDING | FOLLOWING }
| { ROWS } BETWEEN UNBOUNDED PRECEDING AND <n> { PRECEDING | FOLLOWING }
| { ROWS } BETWEEN <n> { PRECEDING | FOLLOWING } AND UNBOUNDED FOLLOWING
}
매개변수
<FUNCTION>
윈도우 함수의 이름입니다. 모든 집계 함수와 다음 특수 윈도우 함수가 포함됩니다: DENSE_RANK(), FIRST_VALUE(), LAG(), LAST_VALUE(), LEAD(), RANK(), ROW_NUMBER(), NTH_VALUE(), PERCENT_RANK(), CUME_DIST(), NTILE().
<ARGUMENTS>
선택 사항입니다. 윈도우 함수의 입력 인수입니다. 인수의 타입과 개수는 사용하는 함수에 따라 달라집니다.
<PARTITION_BY>
선택 사항입니다. GROUP BY와 유사하게 지정된 열을 기준으로 데이터를 그룹화한 다음 각 파티션 내에서 계산을 수행합니다.
<ORDER_BY>
선택 사항입니다. 각 파티션 내의 데이터를 정렬하는 데 사용됩니다. 파티션을 지정하지 않으면 전체 데이터셋을 정렬합니다. 다만 이
ORDER BY는 SQL 문 끝에 오는 일반적인ORDER BY와 다릅니다.OVER절에 지정한 정렬은 해당 파티션 내의 데이터에만 적용되며, SQL 문 끝의ORDER BY는 최종 쿼리 결과에 포함된 모든 행의 순서를 제어합니다. 이 두 가지는 함께 사용할 수 있습니다. 또한ORDER BY를OVER절에 명시적으로 지정하지 않으면 파티션 내 데이터의 순서가 임의로 정해져 최종 결과를 예측하기 어려울 수 있습니다. 정렬 열을 명시적으로 지정하더라도 중복 값이 포함되어 있으면 결과가 여전히 불안정할 수 있습니다. 구체적인 예는 아래 사례를 참조하세요.
<windowFrameClause>
선택 사항입니다. 윈도우 프레임을 정의하는 데 사용됩니다. 현재
RANGE와ROWS, 두 가지 타입을 지원합니다.N PRECEDING/FOLLOWING에서N은 양의 정수이며, 현재 행을 기준으로 슬라이딩 윈도우의 범위를 나타냅니다. 현재는ROWS윈도우에서만 지원되므로 현재 행을 기준으로 한 물리적 오프셋을 나타냅니다.RANGE타입에는 현재 몇 가지 제한이 있습니다. 반드시BOTH UNBOUNDED BOUNDARY또는ONE UNBOUNDED BOUNDARY AND ONE CURRENT ROW여야 합니다. 프레임을 지정하지 않으면 기본적으로RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW가 암묵적으로 적용됩니다.
반환 값
입력 표현식과 동일한 데이터 타입을 반환합니다.
분석 함수 데이터의 고유한 정렬 순서
1. 반환 결과의 비일관성 문제
윈도우 함수의 ORDER BY 절이 데이터의 정렬 순서를 유일하게 결정하지 못하면 행의 순서가 불확정적이 됩니다. 예를 들어 ORDER BY 표현식의 결과에 중복 값이 있는 경우가 이에 해당합니다. 이 경우 쿼리를 여러 번 실행할 때마다 해당 행의 반환 순서가 달라져 윈도우 함수의 결과가 일관되지 않을 수 있습니다.
다음 예는 쿼리를 연속으로 실행했을 때 서로 다른 결과가 반환되는 상황을 보여줍니다. 이러한 비일관성은 주로 ORDER BY date_time이 SUM 윈도우 함수에 대해 정렬 순서를 유일하게 결정하지 못하기 때문에 발생합니다.
CREATE TABLE test_window_order
(item_id int,
date_time date,
sales double)
distributed BY hash(item_id)
properties("replication_num" = 1);
INSERT INTO test_window_order VALUES
(1, '2024-07-01', 100),
(2, '2024-07-01', 100),
(3, '2024-07-01', 140);
SELECT
item_id, date_time, sales,
sum(sales) OVER (ORDER BY date_time ROWS BETWEEN
UNBOUNDED PRECEDING AND CURRENT ROW) sum
FROM
test_window_order;
정렬 열인 date_time에 중복 값이 있으므로 다음 두 가지 쿼리 결과가 나타날 수 있습니다.
+---------+------------+-------+------+
| item_id | date_time | sales | sum |
+---------+------------+-------+------+
| 1 | 2024-07-01 | 100 | 100 |
| 3 | 2024-07-01 | 140 | 240 |
| 2 | 2024-07-01 | 100 | 340 |
+---------+------------+-------+------+
3 rows in set (0.03 sec)
+---------+------------+-------+------+
| item_id | date_time | sales | sum |
+---------+------------+-------+------+
| 2 | 2024-07-01 | 100 | 100 |
| 1 | 2024-07-01 | 100 | 200 |
| 3 | 2024-07-01 | 140 | 340 |
+---------+------------+-------+------+
3 rows in set (0.02 sec)
2. 해결 방법
이 문제를 해결하려면 item_id처럼 고유한 값을 가진 열을 ORDER BY 절에 추가하여 정렬 순서의 유일성을 보장할 수 있습니다.
SELECT
item_id,
date_time,
sales,
sum(sales) OVER (
ORDER BY item_id,
date_time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum
FROM
test_window_order;
이렇게 하면 일관된 쿼리 결과를 얻을 수 있습니다.
+---------+------------+-------+------+
| item_id | date_time | sales | sum |
+---------+------------+-------+------+
| 1 | 2024-07-01 | 100 | 100 |
| 2 | 2024-07-01 | 100 | 200 |
| 3 | 2024-07-01 | 140 | 340 |
+---------+------------+-------+------+
3 rows in set (0.03 sec)