COUNT

COUNT (개수)

지정된 열의 NULL이 아닌 레코드 수 또는 총 레코드 수를 반환해요.

참조: COUNT_IF, MAX, MIN, SUM

출처: Snowflake SQL Reference - COUNT

본문

구문

집계 함수

COUNT( [ DISTINCT ] <expr1> [, <expr2> ... ] )

COUNT(*)

COUNT(<alias>.*)

윈도우 함수

COUNT( [ DISTINCT ] <expr1> [, <expr2> ... ] ) OVER (
                                                     [ PARTITION BY <expr3> ]
                                                     [ ORDER BY <expr4> [ { ASC | DESC } ] [ NULLS { FIRST | LAST } ] ]
                                                     [ <window_frame> ]
                                                     )

window_frame의 자세한 구문은 Window function syntax and usage를 참고해요.

인자

expr1

열 이름으로, 한정된 이름일 수 있어요(예: database.schema.table.column_name).

expr2

원한다면 추가 열 이름을 포함할 수 있어요. 예를 들어 성과 이름의 고유 조합 수를 셀 수 있어요.

expr3

결과를 여러 윈도우로 나누길 원하면 파티션할 열이에요.

expr4

각 윈도우를 정렬할 열이에요. 최종 결과 집합을 정렬하는 ORDER BY 절과는 별개란 점에 유의해요.

*

총 레코드 수를 반환해요.

함수에 와일드카드를 전달할 때 와일드카드를 테이블 이름이나 별칭으로 한정할 수 있어요. 예를 들어 mytable이라는 이름의 테이블에서 모든 열을 전달하려면 다음을 지정해요:

(mytable.*)

또한 필터링에 ILIKE 및 EXCLUDE 키워드를 사용할 수 있어요:

  • ILIKE는 지정된 패턴과 일치하는 열 이름을 필터링해요. 패턴은 하나만 허용돼요. 예: (* ILIKE 'col1%')
  • EXCLUDE는 지정된 열과 일치하지 않는 열 이름을 필터링해요. 예: (* EXCLUDE col1), (* EXCLUDE (col1, col2))

이러한 키워드를 사용할 때 한정자(qualifiers)가 유효해요. 다음 예시는 ILIKE 키워드를 사용해 mytable 테이블에서 col1% 패턴과 일치하는 모든 열을 필터링해요:

(mytable.* ILIKE 'col1%')

ILIKE와 EXCLUDE 키워드는 단일 함수 호출에서 결합할 수 없어요.

한정되지 않고 필터링되지 않은 와일드카드(*)를 지정하면 함수는 NULL 값이 있는 레코드를 포함해 총 레코드 수를 반환해요.

필터링을 위해 ILIKE나 EXCLUDE 키워드가 있는 와일드카드를 지정하면 함수는 NULL 값이 있는 레코드를 제외해요.

이 함수의 경우 ILIKE와 EXCLUDE 키워드는 SELECT 목록이나 GROUP BY 절에서만 유효해요.

ILIKE 및 EXCLUDE 키워드에 대한 자세한 내용은 SELECT의 "Parameters" 섹션을 참고해요.

alias.*

NULL 값을 포함하지 않는 레코드 수를 반환해요. 예시는 Examples를 참고해요.

반환 값

NUMBER 타입의 값을 반환해요.

사용상 주의사항

  • 이 함수는 JSON null(VARIANT NULL)을 SQL NULL로 취급해요.
  • NULL 값과 집계 함수에 대한 자세한 내용은 Aggregate functions and NULL values를 참고해요.
  • 이 함수가 집계 함수로 호출될 때: DISTINCT 키워드를 사용하면 모든 열에 적용돼요. 예를 들어 DISTINCT col1, col2, col3은 열 col1, col2, col3의 서로 다른 조합 수를 반환함을 의미해요. 예를 들어 데이터가 1,1,1 / 1,1,1 / 1,1,1 / 1,1,2라고 가정할 때, 이 경우 함수는 세 열에 있는 값의 서로 다른 조합 수인 2를 반환해요.
  • 이 함수가 ORDER BY 절을 포함한 OVER 절을 가진 윈도우 함수로 호출될 때: 윈도우 프레임이 필수예요. 명시적으로 지정하지 않으면 다음의 암시적 윈도우 프레임이 사용돼요: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. 윈도우 프레임에 대한 자세한 내용은 Window function syntax and usage를 참고해요.
  • DISTINCT는 고유 집합이 단일 열에 적용될 때 ORDER BY를 포함한 OVER 절과 함께 사용할 수 있어요. 예: COUNT(DISTINCT <expr>) OVER (... ORDER BY <orderexpr> [...]). COUNT(DISTINCT <expr1>, <expr2>, ...) 같이 여러 열 표현식을 참조하는 고유 개수는 OVER 절에 ORDER BY도 포함되면 유효하지 않아요.
  • 조건과 일치하는 행 수를 반환하려면 COUNT_IF를 사용해요.
  • 가능하면 행 접근 정책(row access policy)이 없는 테이블과 뷰에 COUNT 함수를 사용해요. 이 함수가 있는 쿼리는 행 접근 정책이 없는 테이블이나 뷰에서 더 빠르고 정확해요. 성능 차이의 이유는 Snowflake가 테이블과 뷰에 대한 통계를 유지하고, 이 최적화로 단순 쿼리를 더 빠르게 실행할 수 있기 때문이에요. 행 접근 정책이 테이블이나 뷰에 설정되어 있고 쿼리에서 COUNT 함수가 사용되면 Snowflake는 각 행을 스캔하고 사용자가 행을 볼 수 있는지 결정해야 해요.

예시

다음 예시들은 NULL 값이 있는 데이터에 COUNT 함수를 사용해요.

테이블을 만들고 값을 삽입해요:

CREATE TABLE basic_example (i_col INTEGER, j_col INTEGER);

INSERT INTO basic_example VALUES
  (11, 101),
  (11, 102),
  (11, NULL),
  (12, 101),
  (NULL, 101),
  (NULL, 102);

테이블 조회:

SELECT * FROM basic_example ORDER BY i_col;
+-------+-------+
| I_COL | J_COL |
|-------+-------|
|    11 |   101 |
|    11 |   102 |
|    11 |  NULL |
|    12 |   101 |
|  NULL |   101 |
|  NULL |   102 |
+-------+-------+
SELECT COUNT(*) AS "All",
    COUNT(* ILIKE 'i_c%') AS "ILIKE",
    COUNT(* EXCLUDE i_col) AS "EXCLUDE",
    COUNT(i_col) AS "i_col",
    COUNT(DISTINCT i_col) AS "DISTINCT i_col",
    COUNT(j_col) AS "j_col",
    COUNT(DISTINCT j_col) AS "DISTINCT j_col"
  FROM basic_example;
+-----+-------+---------+-------+----------------+-------+----------------+
| All | ILIKE | EXCLUDE | i_col | DISTINCT i_col | j_col | DISTINCT j_col |
|-----+-------+---------+-------+----------------+-------+----------------|
|   6 |     4 |       5 |     4 |              2 |     5 |              2 |
+-----+-------+---------+-------+----------------+-------+----------------+

이 출력의 All 열은 COUNT에 대해 한정되지 않고 필터링되지 않은 와일드카드를 지정하면 함수가 NULL 값이 있는 행을 포함해 테이블의 총 행 수를 반환함을 보여줘요. 출력의 다른 열은 열 또는 필터링이 있는 와일드카드를 지정하면 함수가 NULL 값이 있는 행을 제외함을 보여줘요.

다음 쿼리는 GROUP BY 절과 함께 COUNT 함수를 사용해요:

SELECT i_col, COUNT(*), COUNT(j_col)
  FROM basic_example
  GROUP BY i_col
  ORDER BY i_col;
+-------+----------+--------------+
| I_COL | COUNT(*) | COUNT(J_COL) |
|-------+----------+--------------|
|    11 |        3 |            2 |
|    12 |        1 |            1 |
|  NULL |        2 |            2 |
+-------+----------+--------------+

다음 예시는 COUNT(alias.*)가 NULL 값을 포함하지 않는 행 수를 반환함을 보여줘요. basic_example 테이블은 총 6행이지만, 3행은 적어도 하나의 NULL 값을 갖고, 나머지 3행은 NULL 값이 없어요.

SELECT COUNT(n.*) FROM basic_example AS n;
+------------+
| COUNT(N.*) |
|------------|
|          3 |
+------------+

다음 예시는 JSON null(VARIANT NULL)이 COUNT 함수에 의해 SQL NULL로 취급됨을 보여줘요.

SQL NULL과 JSON null 값을 모두 포함하는 데이터로 테이블을 만들고 삽입해요:

CREATE OR REPLACE TABLE count_example_with_variant_column (
  i_col INTEGER,
  j_col INTEGER,
  v VARIANT
);
BEGIN WORK;
INSERT INTO count_example_with_variant_column (i_col, j_col, v)
  VALUES (NULL, 10, NULL);
INSERT INTO count_example_with_variant_column (i_col, j_col, v)
  SELECT 1, 11, PARSE_JSON('{"Title": null}');
INSERT INTO count_example_with_variant_column (i_col, j_col, v)
  SELECT 2, 12, PARSE_JSON('{"Title": "O"}');
INSERT INTO count_example_with_variant_column (i_col, j_col, v)
  SELECT 3, 12, PARSE_JSON('{"Title": "I"}');
COMMIT WORK;

이 SQL 코드에서 다음에 유의해요:

  • 첫 번째 INSERT INTO 문은 VARIANT 열과 비-VARIANT 열 모두에 SQL NULL을 삽입해요.
  • 두 번째 INSERT INTO 문은 JSON null(VARIANT NULL)을 삽입해요.
  • 마지막 두 INSERT INTO 문은 NULL이 아닌 VARIANT 값을 삽입해요.

데이터 표시:

SELECT i_col, j_col, v, v:Title
  FROM count_example_with_variant_column
  ORDER BY i_col;
+-------+-------+-----------------+---------+
| I_COL | J_COL | V               | V:TITLE |
|-------+-------+-----------------+---------|
|     1 |    11 | {               | null    |
|       |       |   "Title": null |         |
|       |       | }               |         |
|     2 |    12 | {               | "O"     |
|       |       |   "Title": "O"  |         |
|       |       | }               |         |
|     3 |    12 | {               | "I"     |
|       |       |   "Title": "I"  |         |
|       |       | }               |         |
|  NULL |    10 | NULL            | NULL    |
+-------+-------+-----------------+---------+

COUNT 함수가 NULL과 JSON null(VARIANT NULL) 값을 모두 NULL로 취급함을 보여줘요. 테이블에는 네 행이 있어요. 하나는 SQL NULL이고 다른 하나는 JSON null이에요. 두 행 모두 개수에서 제외되므로 개수는 2예요.

SELECT COUNT(v:Title)
  FROM count_example_with_variant_column;
+----------------+
| COUNT(V:TITLE) |
|----------------|
|              2 |
+----------------+

OVER 절과 함께 COUNT(DISTINCT …)를 사용해 시간에 따른 고유 고객 수 계산:

CREATE OR REPLACE TABLE customer_product_sales_fct (
    sale_date DATE,
    sale_id INTEGER,
    customer_id STRING,
    product_id STRING,
    quantity INTEGER,
    sales_amount NUMBER(10, 2)
);

INSERT INTO customer_product_sales_fct VALUES
    ('2026-01-01', 1, 'C001', 'P100', 1, 19.99),
    ('2026-01-02', 2, 'C002', 'P100', 2, 39.98),
    ('2026-01-03', 3, 'C001', 'P100', 1, 19.99),
    ('2026-01-04', 4, 'C003', 'P100', 1, 19.99),
    ('2026-01-05', 5, 'C002', 'P200', 1, 9.99),
    ('2026-01-06', 6, 'C004', 'P100', 3, 59.97),
    ('2026-01-07', 7, 'C003', 'P100', 1, 19.99),
    ('2026-01-08', 8, 'C005', 'P100', 2, 39.98),
    ('2026-01-09', 9, 'C001', 'P200', 1, 9.99),
    ('2026-01-10', 10, 'C006', 'P100', 1, 19.99);

SELECT
    product_id,
    customer_id,
    sale_date,
    sale_id,
    COUNT(DISTINCT customer_id) OVER (
        PARTITION BY product_id
        ORDER BY sale_date
    ) AS distinct_customers_to_date
FROM customer_product_sales_fct
WHERE product_id = 'P100'
ORDER BY sale_date, sale_id;
+------------+-------------+------------+---------+----------------------------+
| PRODUCT_ID | CUSTOMER_ID | SALE_DATE  | SALE_ID | DISTINCT_CUSTOMERS_TO_DATE |
+------------+-------------+------------+---------+----------------------------+
| P100       | C001        | 2026-01-01 | 1       | 1                          |
| P100       | C002        | 2026-01-02 | 2       | 2                          |
| P100       | C001        | 2026-01-03 | 3       | 2                          |
| P100       | C003        | 2026-01-04 | 4       | 3                          |
| P100       | C004        | 2026-01-06 | 6       | 4                          |
| P100       | C003        | 2026-01-07 | 7       | 4                          |
| P100       | C005        | 2026-01-08 | 8       | 5                          |
| P100       | C006        | 2026-01-10 | 10      | 6                          |
+------------+-------------+------------+---------+----------------------------+

더 알아보기