🧚 잠깐만요! Beekeeper Studio는 빠르고 현대적인 오픈 소스 데이터베이스 GUI예요 다운로드
2025년 7월 21일 작성자: Matthew Rathbone

COUNT(DISTINCT column)은 컬럼에 서로 다른 값이 몇 개 있는지 세요. 열 번 나오는 값도 한 번만 세고, NULL은 아예 세지 않아요. 예제는 PostgreSQL, MySQL, SQLite, SQL Server에서 동작해요.

COUNT DISTINCT 사용법

COUNT() 안에서 셀 컬럼이나 표현식 앞에 DISTINCT를 넣으세요:

COUNT(DISTINCT expression)

다른 두 가지 COUNT 형태와 나란히 놓고 보면 가장 이해하기 쉬워요. COUNT(*)는 행 수를, COUNT(column)은 컬럼이 NULL이 아닌 행 수를, COUNT(DISTINCT column)은 NULL이 아닌 서로 다른 값의 수를 세요:

-- Input: orders
-- order_id | customer_id
-- ---------+------------
-- 1        | 1042
-- 2        | 1077
-- 3        | 1042
-- 4        | NULL

SELECT COUNT(*) AS all_rows,
       COUNT(customer_id) AS with_customer,
       COUNT(DISTINCT customer_id) AS customers
FROM orders;

-- Output:
-- all_rows | with_customer | customers
-- ---------+---------------+----------
-- 4        | 3             | 2

주문 4건이 고객 2명에게서 들어왔어요. 1042는 두 번 주문했고, 주문 4에는 고객이 아예 없어요.

알아 둘 규칙

  • NULL은 세지 않아요. 값이 없는 경우도 하나로 세야 한다면 직접 더하세요:
-- Input: the orders table above

SELECT COUNT(DISTINCT customer_id)
       + MAX(CASE WHEN customer_id IS NULL THEN 1 ELSE 0 END) AS customers_and_guests
FROM orders;
-- Output: 3
  • MySQL과 SQL Server는 기본적으로 대소문자를 구분하지 않아요. 그래서 'SQL'과 'sql'을 하나의 값으로 세요. 대소문자를 구분하지 않아야 할 때는 LOWER(tag)를 세세요:
-- Input: tags
-- post_id | tag
-- --------+---------
-- 1       | SQL
-- 2       | sql
-- 3       | Postgres

SELECT COUNT(DISTINCT tag) FROM tags;
-- Output: 3 (2 in MySQL and SQL Server)

SELECT COUNT(DISTINCT LOWER(tag)) FROM tags;
-- Output: 2
  • DISTINCT는 SUM과 AVG 안에서도 동작하지만, 중복된 행이 아니라 중복된 값을 제거해요. 가격이 같은 서로 다른 두 상품은 한 번만 더해져요:
-- Input: order_lines
-- product  | price
-- ---------+------
-- Pen      | 2.00
-- Pencil   | 2.00
-- Notebook | 5.00

SELECT SUM(price) AS total, SUM(DISTINCT price) AS distinct_total FROM order_lines;

-- Output:
-- total | distinct_total
-- ------+---------------
-- 9.00  | 7.00

대체 문법

COUNT(DISTINCT ...)는 컬럼 하나만 받아요. 여러 컬럼의 서로 다른 조합을 세려면 DISTINCT 서브쿼리의 행 수를 세세요. PostgreSQL과 MySQL에는 축약 문법도 있어요:

-- Input: orders
-- order_id | customer_id | product_id
-- ---------+-------------+-----------
-- 1        | 1           | 23
-- 2        | 12          | 3
-- 3        | 1           | 23
-- 4        | 12          | 5

SELECT COUNT(*) FROM (SELECT DISTINCT customer_id, product_id FROM orders) AS pairs;
-- Output: 3

-- PostgreSQL
SELECT COUNT(DISTINCT (customer_id, product_id)) FROM orders;
-- Output: 3

-- MySQL
SELECT COUNT(DISTINCT customer_id, product_id) FROM orders;
-- Output: 3

CONCAT()으로 컬럼들을 하나의 문자열로 이어 붙이는 방식도 볼 수 있어요. 이때는 구분자가 꼭 필요해요. 구분자가 없으면 고객 1과 상품 23, 고객 12와 상품 3이 모두 '123'이 돼요:

-- Input: the orders table above

SELECT COUNT(DISTINCT CONCAT(customer_id, product_id)) FROM orders;
-- Output: 2

SELECT COUNT(DISTINCT CONCAT(customer_id, '_', product_id)) FROM orders;
-- Output: 3

정확한 distinct 카운트는 모든 값을 정렬하거나 해시해야 해서 아주 큰 테이블에서는 느려져요. SQL Server에는 APPROX_COUNT_DISTINCT()가 있는데, 더 빠르고 97%의 경우 정확한 값과 2% 이내의 오차를 보여요:

-- SQL Server
-- Input: the orders table above

SELECT APPROX_COUNT_DISTINCT(customer_id) AS customers FROM orders;
-- Output: 2

COUNT DISTINCT는 언제 써야 할까요?

질문이 “행이 몇 개인가?”가 아니라 “서로 다른 …이 몇 개인가?”라면 COUNT DISTINCT를 쓰세요. 이런 질문은 대부분 다음 네 가지 중 하나에 해당해요.

고유 방문자, 고객, 상품 수 세기

방문, 주문, 판매 로그에는 같은 방문자, 고객, 상품이 반복해서 기록돼요. ID에 COUNT DISTINCT를 쓰면 이 행들이 실제 인원수로 바뀌어요.

그룹별 고유 값 세기

GROUP BY를 추가하면 그룹마다 distinct 카운트를 하나씩 얻을 수 있어요. 과목별 학생 수, 판매자별 상품 수, 월별 고객 수처럼요.

컬럼 조합의 고유 값 세기

두 컬럼이 모두 일치해야 두 행이 “같은” 경우가 있어요. 같은 사용자의 같은 종류의 이슈나, 두 공항 사이의 같은 노선처럼요. 이런 조합은 “대체 문법”에 있는 다중 컬럼 방식 중 하나로 세세요.

조건을 만족하는 고유 값 세기

COUNT(DISTINCT ...) 안에 CASE 표현식을 넣으면 일부 행만 셀 수 있어요. CASE가 원하지 않는 행에 NULL을 반환하고 NULL은 세지 않으니, 쿼리 하나로 필터링된 카운트 여러 개를 나란히 얻을 수 있어요.

COUNT DISTINCT 실전 예제

월간 활성 사용자

9월에 무엇이든 활동한 사용자 수를 세요. 몇 번 다시 방문했든 상관없어요:

-- Input: events
-- event_id | user_id | event_date
-- ---------+---------+-----------
-- 1        | 301     | 2026-08-30
-- 2        | 302     | 2026-09-02
-- 3        | 302     | 2026-09-15
-- 4        | 305     | 2026-09-21
-- 5        | 302     | 2026-10-01

SELECT COUNT(DISTINCT user_id) AS active_users
FROM events
WHERE event_date >= '2026-09-01' AND event_date < '2026-10-01';
-- Output: 2

판매자별 판매 상품 수

COUNT(*)는 판매자별 판매 건수를, COUNT(DISTINCT product)는 그 판매에 포함된 서로 다른 상품 수를 알려 줘요:

-- Input: sales
-- vendor     | product  | color
-- -----------+----------+------
-- Acme       | Mug      | Red
-- Acme       | Mug      | Blue
-- Acme       | Mug      | Red
-- Acme       | Tote Bag | Red
-- Brightside | Notebook | Black

SELECT vendor, COUNT(*) AS sales, COUNT(DISTINCT product) AS products
FROM sales
GROUP BY vendor;

-- Output:
-- vendor     | sales | products
-- -----------+-------+---------
-- Acme       | 4     | 2
-- Brightside | 1     | 1

항공사 운항 노선

노선은 출발지와 도착지의 조합이에요. LHR에서 JFK로 가는 항공편 두 개는 한 노선이지만, JFK에서 LHR로 가는 건 다른 노선이에요:

-- Input: flights
-- flight_no | origin | destination
-- ----------+--------+------------
-- 101       | LHR    | JFK
-- 105       | LHR    | JFK
-- 102       | JFK    | LHR
-- 301       | LHR    | LAX

SELECT COUNT(*) AS routes
FROM (SELECT DISTINCT origin, destination FROM flights) AS r;
-- Output: 3

구매 가격대별 고객 수

상품 100~200을 구매한 고객 수를 센 다음, 주문 가격대별로 나눠요. 고객 7은 저렴한 주문을 두 번 했지만 한 번만 세고, 고객 15의 상품은 범위를 벗어나요:

-- Input: orders
-- order_id | customer_id | product_id | price
-- ---------+-------------+------------+-------
-- 1        | 7           | 105        | 25.00
-- 2        | 7           | 142        | 40.00
-- 3        | 9           | 150        | 120.00
-- 4        | 12          | 188        | 310.00
-- 5        | 15          | 260        | 30.00

SELECT
  COUNT(DISTINCT customer_id) AS customers,
  COUNT(DISTINCT CASE WHEN price BETWEEN 1 AND 50 THEN customer_id END) AS low_spenders,
  COUNT(DISTINCT CASE WHEN price BETWEEN 51 AND 150 THEN customer_id END) AS mid_spenders,
  COUNT(DISTINCT CASE WHEN price > 150 THEN customer_id END) AS high_spenders
FROM orders
WHERE product_id BETWEEN 100 AND 200;

-- Output:
-- customers | low_spenders | mid_spenders | high_spenders
-- ----------+--------------+--------------+--------------
-- 3         | 1            | 1            | 1

두 가격대에 모두 주문이 있는 고객은 양쪽에서 모두 세요.

COUNT DISTINCT 더 알아보기

이 블로그의 글:

공식 문서:

Beekeeper Studio는 무료 오픈 소스 데이터베이스 GUI예요

지금까지 써 본 SQL 쿼리 & 에디터 도구 중 최고예요. 데이터베이스 관리에 필요한 모든 게 다 있어요. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio는 빠르고 직관적이며 사용하기 쉬워요. 다양한 데이터베이스를 지원하고 Windows, Mac, Linux에서 모두 잘 작동해요.

Beekeeper의 Linux 버전은 100% 모든 기능을 갖추고 있어요. 대충 만든 부분도, 빠진 기능도 없어요.

Beekeeper Studio 사용자 후기

★★★★★
"Beekeeper Studio가 기존 SQL 작업 방식을 완전히 바꿔 놓았어요. 빠르고 직관적이라 데이터베이스 작업이 다시 즐거워졌어요."
— Alex K., 데이터베이스 개발자
★★★★★
"여러 데이터베이스 GUI를 써 봤지만, Beekeeper는 기능과 단순함 사이의 균형이 완벽해요. 그냥 잘 돼요."
— Sarah M., 풀스택 엔지니어

SQL 작업 방식을 개선할 준비가 되셨나요?

download 무료 다운로드