DAX DISTINCTCOUNT 함수 정리: 고유 값 개수와 합계가 안 맞는 이유

“우리 가게에 온 고객이 몇 명이지?”라고 물으면 주문 건수와는 다른 답이 필요합니다. 한 사람이 여러 번 주문했을 수 있으니까요. 이럴 때 쓰는 함수가 DISTINCTCOUNT입니다. 문법은 단순한데, 빈 값을 한 개의 값으로 센다는 점과 합계 줄이 각 줄의 합과 맞지 않는다는 점 때문에 처음에는 자주 당황합니다. 이 글에서는 그 두 가지를 중심으로, 앞서 정리한 COUNT, COUNTA, COUNTROWS와 어디서 갈리는지, 그리고 실무에서 자주 쓰는 세 가지 상황(고객 수, 월별 활성 고객, 고객당 평균 주문 수)을 같은 데이터로 정리합니다.

문법

DISTINCTCOUNT( <열> )

열 하나를 받아서 서로 다른 값이 몇 개인지를 돌려줍니다. Microsoft 문서에 따르면 열의 데이터 형식은 어떤 것이든 상관없습니다. 셀 행이 하나도 없으면 빈 값을 돌려줍니다.

Power BI Desktop에서 측정값으로 만들기

메뉴 이름은 Power BI 버전과 언어 설정에 따라 조금 다를 수 있다는 점을 먼저 말씀드립니다. 일반적인 순서는 이렇습니다.

  1. 보고서 보기에서 오른쪽 필드 창의 테이블(예: 주문)을 선택합니다.
  2. 상단 리본에서 “새 측정값”(영문판은 New measure)을 누릅니다.
  3. 수식 입력줄에 고객수 = DISTINCTCOUNT( 주문[고객] )처럼 이름과 식을 적고 Enter를 누릅니다.
  4. 만든 측정값을 카드 시각화에 올리고, 월이나 분류 같은 열과 함께 표에 올려 합계 줄이 어떻게 나오는지 확인합니다.

예제 데이터

설명하려고 만든 가상 데이터입니다. 5번 주문은 고객 정보가 비어 있습니다. 결과는 Power BI에서 돌린 화면이 아니라 직접 센 값이니, 같은 식을 본인 데이터에 적용해서 확인해 보세요.

주문월고객분류
13월김노트북
23월김마우스
33월이노트북
44월박마우스
54월(빈 값)모니터
64월이마우스

주문은 모두 6건이니 COUNTROWS( 주문 )은 6입니다. 고객 열에 값이 있는 행은 5개라서 COUNT( 주문[고객] )은 5입니다. 그렇다면 고객은 몇 명일까요?

실무 시나리오 1: 고객 수, 그리고 빈 값도 하나의 값으로 센다

고객수 = DISTINCTCOUNT( 주문[고객] )

결과는 4입니다. 김, 이, 박 세 명에 빈 값이 하나 더해졌습니다. Microsoft 문서와 DAX Guide 모두 DISTINCTCOUNT가 BLANK를 하나의 값으로 센다고 설명합니다. 사람이 세 명인데 4가 나오는 이유가 이것입니다. 빈 값을 빼고 세고 싶다면 DISTINCTCOUNTNOBLANK를 씁니다.

고객수_빈값제외 = DISTINCTCOUNTNOBLANK( 주문[고객] )

결과는 3입니다. Microsoft 문서의 예제도 같은 구조로, 종료일 열에서 DISTINCTCOUNTNOBLANK는 2, DISTINCTCOUNT는 3이 나오는 것을 보여줍니다. 둘 사이의 차이가 바로 빈 값 하나입니다.

함수질문예제 결과
COUNTROWS( 주문 )주문이 몇 건인가6
COUNT( 주문[고객] )고객이 적힌 주문이 몇 건인가5
DISTINCTCOUNT( 주문[고객] )서로 다른 고객 값이 몇 개인가(빈 값 포함)4
DISTINCTCOUNTNOBLANK( 주문[고객] )서로 다른 고객이 몇 명인가(빈 값 제외)3

실무 시나리오 2: 합계 줄이 소계의 합과 다르다

분류별 고객 수를 표로 만들어 보겠습니다.

분류고객수(DISTINCTCOUNT)해당하는 고객
노트북2김, 이
마우스3김, 박, 이
모니터1(빈 값)
합계4김, 이, 박, (빈 값)

세 줄을 더하면 2 + 3 + 1 = 6인데 합계 줄은 4입니다. 오류가 아닙니다. 김과 이는 노트북과 마우스 양쪽에서 구매했기 때문에 분류별로는 각각 한 번씩 세어지지만, 전체로 보면 한 사람입니다. Microsoft 문서도 고유 값 개수의 합계는 더해지는 값이 아니라고 따로 설명하고, 합이 맞아야 하는 경우라면 COUNT나 COUNTROWS처럼 행을 세는 함수를 고려하라고 안내합니다. 다만 그 함수들은 “행 수”를 세는 것이라 의미가 다르다는 점도 함께 짚습니다.

월별로 나누어도 같은 일이 생깁니다. 3월 고객은 김과 이로 2명, 4월 고객은 박, 빈 값, 이로 3명입니다. 두 달을 더하면 5인데, 전체 고객 수는 4입니다. 이가 3월과 4월 양쪽에 있기 때문입니다. 이 값은 “월별 활성 고객 수”로는 올바르지만, 이것을 더해서 “연간 고객 수”를 만들면 틀립니다.

월별활성고객 = DISTINCTCOUNTNOBLANK( 주문[고객] )
월월별활성고객(빈 값 제외)해당하는 고객
3월2김, 이
4월2박, 이
합계3김, 이, 박

빈 값을 뺀 월별 활성 고객은 두 달 모두 2명이고, 합계 줄은 3명입니다. 2 + 2 = 4와 3은 다릅니다. 이 차이가 곧 “두 달 연속으로 구매한 고객”(이)이 중복되어 세어진 정도입니다. 보고서에서 이 차이가 중요한 이유는, 합계를 보고 “월별 숫자가 틀렸나?” 하고 의심하기 쉽기 때문입니다. 질문이 “그 달에 구매한 고객이 몇 명인가”라면 월별 값이 맞고, “기간 전체에서 구매한 고객이 몇 명인가”라면 합계 줄이 맞습니다.

실무 시나리오 3: 조건과 함께 세기, 그리고 고객당 평균 주문 수

마우스를 산 고객 수는 CALCULATE로 조건을 바꿔서 셉니다. CALCULATE가 필터를 바꾸는 원리는 CALCULATE 함수 글에 정리해 두었습니다.

마우스구매고객수 =
CALCULATE(
    DISTINCTCOUNT( 주문[고객] ),
    주문[분류] = "마우스"
)

마우스 주문은 2번(김), 4번(박), 6번(이)이라 결과는 3입니다. 또 “고객 한 명이 평균 몇 번 주문했는가”는 주문 건수를 고유 고객 수로 나누면 됩니다.

고객당평균주문수 =
DIVIDE(
    COUNT( 주문[고객] ),
    DISTINCTCOUNTNOBLANK( 주문[고객] )
)

고객이 적힌 주문 5건을 고유 고객 3명으로 나누니 5 ÷ 3 = 약 1.67입니다. 분자와 분모에서 빈 값을 같은 기준으로 처리하는 것이 중요합니다. 분자에 COUNTROWS( 주문 )(6)을 쓰고 분모에 DISTINCTCOUNTNOBLANK(3)를 쓰면 6 ÷ 3 = 2가 되어, 고객이 없는 주문까지 고객당 주문으로 계산하는 오류가 생깁니다. 이 값은 재구매 정도를 가늠하는 간단한 지표로 자주 쓰입니다.

COUNTROWS와 DISTINCT로 풀어 쓰기

DAX Guide에 따르면 아래 두 식은 같은 결과를 냅니다.

DISTINCTCOUNT( 주문[고객] )
COUNTROWS( DISTINCT( 주문[고객] ) )

그래서 DISTINCTCOUNT는 “고유 값 목록을 만든 뒤 행 수를 센다”는 뜻으로 읽으면 됩니다.

성능: 왜 느릴 수 있을까

SQLBI의 분석에 따르면 DISTINCTCOUNT는 합계처럼 중간 결과를 합쳐서 구할 수 없는 “비가산” 집계라서, 보고서의 각 셀마다 따로 계산해야 하는 부담이 있습니다. 열의 고유 값이 매우 많거나(카디널리티가 높거나), 셀마다 서로 다른 필터가 적용되는 복잡한 보고서에서는 느려질 수 있습니다. 같은 글은 단순한 보고서에서는 DISTINCTCOUNT가 대체로 낫고, 느리다고 느껴질 때는 DAX Studio 같은 도구로 실제 성능을 측정한 뒤에 다른 방식을 고려하라고 권합니다. 근사값으로 충분하다면 DAX Guide는 APPROXIMATEDISTINCTCOUNT라는 대안을 소개합니다.

쓰지 말아야 할 때

  • 단순히 행 수가 필요할 때: COUNTROWS가 알맞습니다.
  • 소계를 더해서 합계를 만들어야 할 때: 고유 값 개수는 더해지지 않습니다.
  • 빈 값이 섞인 열에서 “사람 수”를 셀 때: 빈 값을 뺄지 정하세요. 빼려면 DISTINCTCOUNTNOBLANK입니다.
  • 고유 값이 수백만 개인 열을 여러 셀에서 반복 계산할 때: 속도를 먼저 점검하세요.

알아둘 점

  • 인수는 열 하나뿐입니다. 테이블은 넣을 수 없습니다.
  • DirectQuery 모드에서는 계산 열이나 행 수준 보안 규칙 안에서 쓸 수 없다고 Microsoft 문서에 적혀 있습니다. DAX Guide는 측정값과 계산 열에서 지원된다고 적어 두어 설명이 다르니, 쓰는 환경에서 직접 확인해 보세요.
  • 지역 설정에 따라 인수 구분자가 쉼표 대신 세미콜론일 수 있습니다. 식을 붙여 넣었는데 오류가 난다면 먼저 확인해 보세요.

자주 하는 실수

  1. 빈 값이 하나 더 세어져서 사람 수보다 1 크게 나옴: 빈 값을 뺄지 정하세요. 빼려면 DISTINCTCOUNTNOBLANK입니다.
  2. 합계 줄이 소계의 합과 다르다고 오류로 판단: 고유 값 개수는 원래 그렇습니다.
  3. 주문 건수를 고객 수로 착각: 한 사람이 여러 번 주문하면 두 값은 달라집니다.
  4. 분자와 분모의 빈 값 처리 기준이 다름: 비율을 구할 때 기준을 통일하세요.

비슷한 함수

  • DISTINCTCOUNTNOBLANK: 빈 값을 세지 않는 형태
  • COUNTROWS, COUNT, COUNTA: 행 수와 값이 있는 행 수
  • DISTINCT, VALUES: 고유 값 목록을 테이블로 돌려주는 함수

정리

DISTINCTCOUNT는 “서로 다른 값의 개수”를 세는 함수이고, 빈 값도 하나의 값으로 센다는 것과 합계가 소계의 합과 달라진다는 것, 이 두 가지가 핵심입니다. 질문이 사람 수인지 건수인지, 그리고 월별 값과 기간 전체 값 중 무엇을 묻는지부터 정하면 COUNTROWS와 DISTINCTCOUNT 중 무엇을 쓸지 자연스럽게 정해집니다. 예제는 가상 데이터이니 본인 모델의 열 이름으로 바꿔 직접 확인해 보시고, 동작은 버전에 따라 다를 수 있어 공식 문서도 함께 보시길 권합니다.

참고한 자료

  • Microsoft Learn, DISTINCTCOUNT function (DAX): https://learn.microsoft.com/en-us/dax/distinctcount-function-dax
  • Microsoft Learn, DISTINCTCOUNTNOBLANK function (DAX): https://learn.microsoft.com/en-us/dax/distinctcountnoblank-function-dax
  • DAX Guide, DISTINCTCOUNT: https://dax.guide/distinctcount/
  • SQLBI, Analyzing the performance of DISTINCTCOUNT in DAX: https://www.sqlbi.com/articles/analyzing-distinctcount-performance-in-dax/

댓글 남기기