DAX COUNTROWS 함수 정리: 행 수를 셀 때 COUNT보다 먼저 떠올릴 함수

“주문이 몇 건이지?”를 계산할 때 열 하나를 골라 COUNT를 쓰는 사람이 많습니다. 틀린 방법은 아닌데, Microsoft 문서에는 이런 상황에서 COUNTROWS를 쓰라는 권고가 따로 있습니다. 이 글에서는 COUNTROWS가 어떤 함수인지, 왜 권장되는지, 그리고 필터, 관계, 고유 값 세기와 함께 쓰는 대표 패턴을 같은 데이터로 정리합니다. 앞서 쓴 COUNT 함수 글과 COUNTA 함수 글의 다음 이야기이기도 합니다.

문법

COUNTROWS( [<테이블>] )

인수는 테이블 하나이고, 그 테이블의 행 수를 정수로 돌려줍니다. 인수는 모델에 있는 테이블 이름일 수도 있고, 테이블을 돌려주는 식일 수도 있습니다. 대괄호로 표시했듯 인수를 생략할 수도 있는데, 그러면 식이 속한 테이블이 기본값으로 쓰입니다(Microsoft 문서). DAX Guide는 생략이 가능해도 테이블을 명시하는 쪽이 읽기 좋고 관리하기 쉽다고 권합니다. 센 결과가 0행이면 0이 아니라 빈 값(BLANK)이 반환됩니다.

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

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

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

예제 데이터

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

고객
고객ID이름
A김
B이
C박
주문
주문고객ID금액배송일
1A303/2
2A203/3
3B50(빈 값)
4A103/5
5B403/6

기본: 테이블의 행 수

총주문건수 = COUNTROWS( 주문 )

주문 표에는 5행이 있으니 결과는 5입니다. 고객별 표에 올리면 필터가 적용되어 김 3, 이 2로 나뉩니다. 이 측정값은 보고서의 각 셀이 가진 필터 상태에 맞춰 다시 계산됩니다.

왜 COUNT 대신 COUNTROWS인가

같은 값을 열 하나로 셀 수도 있습니다.

배송입력건수 = COUNT( 주문[배송일] )   -- 4
총주문건수   = COUNTROWS( 주문 )         -- 5

배송일 열에는 빈 값이 하나 있어서 COUNT는 4, COUNTROWS는 5입니다. 둘이 같은 값을 내는 경우는 “세는 열에 빈 값이 없을 때”뿐이라는 것이 Microsoft 문서의 설명입니다. 그래서 문서는 테이블의 행 수를 세려는 의도라면 항상 COUNTROWS를 쓰라고 권하며, 이유를 세 가지로 듭니다.

  • 더 효율적이라서 성능이 낫다
  • 테이블의 어떤 열에 빈 값이 있어도 영향을 받지 않는다
  • 식의 의도가 분명해서 읽는 순간 무슨 뜻인지 알 수 있다

특정 열에 값이 있는 행만 세고 싶을 때가 COUNT를 쓰는 자리입니다. 둘의 차이는 데이터를 받은 직후 입력 완성도를 점검할 때 그대로 쓸 수 있습니다.

배송일입력률 =
DIVIDE( COUNT( 주문[배송일] ), COUNTROWS( 주문 ) )

4 ÷ 5 = 80%입니다. 분모에는 열의 값 유무와 상관없는 COUNTROWS를 써야 합니다. 분모까지 COUNT( 주문[배송일] )로 쓰면 항상 100%가 나와서 점검이 되지 않습니다.

실무 시나리오 1: 조건에 맞는 행만 세기

“금액이 30 이상인 주문이 몇 건인가”는 테이블을 먼저 거른 뒤 세면 됩니다. FILTER로 테이블을 넘기는 방법과 CALCULATE로 조건을 거는 방법이 있습니다.

큰주문건수 =
COUNTROWS( FILTER( 주문, 주문[금액] >= 30 ) )

큰주문건수_2 =
CALCULATE( COUNTROWS( 주문 ), 주문[금액] >= 30 )

1번(30), 3번(50), 5번(40)이 해당되어 둘 다 3입니다. 큰 주문의 비율은 이렇게 구합니다.

큰주문비율 =
DIVIDE( [큰주문건수_2], [총주문건수] )

3 ÷ 5 = 60%입니다. 어느 쪽을 쓰든 결과는 같지만, SQLBI는 테이블 전체에 FILTER를 거는 것보다 열 하나에 조건을 거는 쪽이 더 가볍고 안전하다고 설명합니다. CALCULATE로 조건을 거는 방식은 CALCULATE 함수 글에 자세히 적어 두었습니다.

실무 시나리오 2: 관계를 따라 세기 (RELATEDTABLE)

Microsoft 문서의 두 번째 예제처럼, 고객 표에 “주문 건수” 계산 열을 만들 수 있습니다. 고객 표와 주문 표가 고객ID로 연결되어 있다고 가정합니다.

주문건수 = COUNTROWS( RELATEDTABLE( 주문 ) )
고객주문건수
김(A)3
이(B)2
박(C)(빈 값)

김은 1, 2, 4번 주문이라 3건, 이는 3, 5번이라 2건입니다. 박은 주문이 한 건도 없으니 0이 아니라 빈 값이 나옵니다. 앞서 말한 “0행이면 BLANK”가 그대로 드러나는 부분입니다. 이 계산 열은 행 컨텍스트가 있는 상태에서 RELATEDTABLE이 “현재 고객의 주문만” 돌려주는 방식으로 동작하며, 행 컨텍스트가 필터로 바뀌는 원리는 SQLBI의 컨텍스트 전환 설명에 잘 정리되어 있습니다.

표에 0으로 보이게 하려면 따로 처리가 필요합니다. 다만 단순히 0을 더하는 방식은 주문이 없는 고객뿐 아니라 다른 항목까지 0으로 늘어나는 부작용이 있다고 SQLBI(빈 값 대신 0을 반환하는 방법)가 설명합니다. 어디까지 0으로 보여줄지는 질문의 성격에 따라 정해야 합니다.

실무 시나리오 3: 고유 값 세기와 단일 선택 확인

DAX Guide는 COUNTROWS를 다른 함수와 조합하는 대표 패턴도 소개합니다.

주문한고객수 = COUNTROWS( DISTINCT( 주문[고객ID] ) )   -- 2 (A, B)

한명만선택됨 = COUNTROWS( VALUES( 주문[고객ID] ) ) = 1

첫 번째 식은 서로 다른 고객ID의 수라서 A와 B, 즉 2입니다. 같은 일을 하는 전용 함수가 DISTINCTCOUNT입니다. 두 번째는 현재 필터에서 고객이 한 명만 남았는지 확인하는 식입니다. 이 결과를 IF와 함께 쓰면 “고객이 한 명 선택됐을 때만 그 고객의 정보를 보여주는” 측정값을 만들 수 있습니다.

선택고객ID =
IF(
    COUNTROWS( VALUES( 주문[고객ID] ) ) = 1,
    VALUES( 주문[고객ID] ),
    "여러 명"
)

슬라이서에서 고객 한 명을 고르면 그 ID가, 아무것도 고르지 않았거나 여러 명이면 “여러 명”이 표시됩니다. 같은 확인을 하는 전용 함수가 따로 있는데, 이는 별도 글에서 다룹니다.

실무 시나리오 4: 배송이 안 된 주문 점검

입력 완성도를 점검하는 김에, “아직 배송일이 비어 있는 주문”의 건수도 바로 셀 수 있습니다. 비어 있는지 확인하는 ISBLANK와 FILTER를 함께 쓰면 됩니다.

미배송건수 =
COUNTROWS(
    FILTER( 주문, ISBLANK( 주문[배송일] ) )
)

배송일이 빈 행은 3번 주문 하나라서 결과는 1입니다. 앞에서 구한 “전체 5건 – 배송일 입력 4건 = 1건”과 같은 값입니다. 같은 값을 서로 다른 식으로 구해서 맞춰 보는 것은 측정값이 의도대로 동작하는지 점검하는 좋은 습관입니다. 이 측정값을 고객별 표에 올리면 이 고객 한 명에게 미배송 주문이 한 건 있다는 것을 바로 확인할 수 있고, 보고서에서는 “독촉이 필요한 주문”을 찾는 출발점이 됩니다.

알아둘 점

  • DirectQuery 모드에서는 계산 열이나 행 수준 보안 규칙 안에서 쓸 수 없다고 Microsoft 문서에 적혀 있습니다. DAX Guide는 측정값에서는 지원된다고 안내합니다.
  • 행 컨텍스트 안에서 호출되면 컨텍스트 전환이 일어납니다.
  • 인수는 열이 아니라 테이블입니다. 헷갈려서 COUNTROWS( 주문[금액] )처럼 쓰면 안 됩니다.
  • 지역 설정에 따라 인수 구분자가 쉼표 대신 세미콜론일 수 있습니다. 식을 붙여 넣었는데 오류가 난다면 먼저 확인해 보세요.

쓰지 말아야 할 때

  • 특정 열의 입력 여부를 세고 싶을 때: 이 경우는 COUNT나 COUNTA가 맞습니다.
  • 서로 다른 값의 수가 목적일 때: COUNTROWS( DISTINCT( … ) )도 되지만 DISTINCTCOUNT가 더 간결합니다.
  • 0건을 0으로 보여줘야 할 때: 아무 처리 없이는 빈 값이 나옵니다.

자주 하는 실수

  1. 행 수를 세는데 열 하나를 골라 COUNT: 그 열이 빈 행은 빠집니다.
  2. 0건이 0이 아니라 빈 값으로 나오는 것을 오류로 생각: 정상 동작입니다.
  3. COUNTROWS에 열을 넣음: 테이블이나 테이블을 돌려주는 식이 들어가야 합니다.
  4. 비율의 분모에 COUNT를 사용: 항상 100%에 가깝게 나옵니다. 분모는 COUNTROWS입니다.

비슷한 함수

  • COUNT, COUNTA: 열에 값이 있는 행을 센다
  • COUNTBLANK: 열의 빈 값을 센다
  • DISTINCTCOUNT: 열의 서로 다른 값을 센다

정리

행 수를 센다는 의도가 있다면 COUNTROWS가 기본이고, 특정 열의 입력 여부를 센다는 의도일 때만 COUNT나 COUNTA를 쓰면 됩니다. 필터를 넘기거나 RELATEDTABLE, DISTINCT와 조합하면 활용 범위도 넓습니다. 예제는 가상 데이터이니 본인 모델의 이름으로 바꿔 직접 확인해 보시고, 동작은 버전에 따라 다를 수 있어 공식 문서도 함께 보시길 권합니다.

참고한 자료

  • Microsoft Learn, COUNTROWS function (DAX): https://learn.microsoft.com/en-us/dax/countrows-function-dax
  • Microsoft Learn, Use COUNTROWS instead of COUNT in DAX: https://learn.microsoft.com/en-us/dax/best-practices/dax-countrows
  • DAX Guide, COUNTROWS: https://dax.guide/countrows/
  • SQLBI, Introducing CALCULATE in DAX: https://www.sqlbi.com/articles/introducing-calculate-in-dax/
  • SQLBI, Context transition in DAX explained visually: https://www.sqlbi.com/articles/context-transition-in-dax-explained-visually/
  • SQLBI, How to return 0 instead of BLANK in DAX: https://www.sqlbi.com/articles/how-to-return-0-instead-of-blank-in-dax/

댓글 남기기