DAX Set Functions – EXCEPT, INTERSECT, UNION and COUNTROWS in DAX: Compare, Merge and Count Tables

September 23, 2026 94 visits

In this article, we will learn how to compare and combine tables using
EXCEPT, INTERSECT, and UNION,
and how to count rows using COUNTROWS. We will use a real-world
job-listing scenario where job data is collected on different days.

📥 Practice Data:
Download Practice Data Free

🎥 Prefer learning through video?
DAX YouTube Playlist

Understanding the Job Data Scenario

Imagine that job listings are collected every day and stored in separate tables such as
Jan-01, Jan-02, Jan-03,
Jan-04, and Jan-05.

A job may appear on multiple days. Therefore, when analyzing daily job listings,
we may want to identify new jobs, find jobs common to multiple days,
combine daily datasets, or simply count how many jobs were collected each day.

Key idea: Table functions such as EXCEPT,
INTERSECT, and UNION are useful when comparing
or combining table expressions in DAX queries.

1. Retrieving the Complete Job Table

Query

DAX Query
EVALUATE
    'Jan-01'

Step-by-step explanation

Step 1: EVALUATE
EVALUATE tells DAX to return the result of a table expression.

Step 2: ‘Jan-01’
‘Jan-01’ is the table expression. Since the table itself is supplied,
DAX returns the rows and columns available in that table.

What will you get?

The query returns the complete job dataset available in the Jan-01 table.
This gives us a starting point for understanding the daily job data.

Key takeaway: EVALUATE ‘Jan-01’ returns the
contents of the Jan-01 table as the query result.

2. Finding Jobs Specific to a Day Using EXCEPT

One common requirement in daily job tracking is to identify jobs that appear on the
latest day but did not appear on the previous day.

For example, we can compare Jan-04 with Jan-03
to identify jobs specific to Jan-04.

Query

DAX Query
EVALUATE
    EXCEPT(
        SELECTCOLUMNS('Jan-04', 
            "Title", 'Jan-04'[Title],
            "Location", 'Jan-04'[Location],
            "Company", 'Jan-04'[Company],
            "Skill", 'Jan-04'[Skills]
        ),
        SELECTCOLUMNS('Jan-03', 
            "Title", 'Jan-03'[Title],
            "Location", 'Jan-03'[Location],
            "Company", 'Jan-03'[Company],
            "Skill", 'Jan-03'[Skills]
        )
    )

Step-by-step explanation

Step 1: SELECTCOLUMNS from Jan-04
The first SELECTCOLUMNS creates a table containing four columns from
Jan-04: Title, Location, Company, and Skill.

Step 2: SELECTCOLUMNS from Jan-03
The second SELECTCOLUMNS creates the same four-column structure from
Jan-03.

Step 3: EXCEPT
EXCEPT compares the first table with the second table and returns
rows that exist in the first table but not in the second table.

Therefore, this query compares the Jan-04 jobs against Jan-03 jobs and returns the
rows that are not present in Jan-03.

Why SELECTCOLUMNS is used here

The two source tables may contain many columns. For the comparison, we only want to
compare the job’s Title, Location,
Company, and Skill.

Both table expressions are therefore shaped into the same column structure before
they are passed to EXCEPT.

Key takeaway: EXCEPT(Table1, Table2) returns the
rows present in Table1 that are not present in Table2.

Real-world use case

This pattern can be useful for identifying newly appearing job listings
when daily job data is collected repeatedly. It can help reduce repeated listings in
a daily job-analysis workflow.


3. Finding Common Jobs Using INTERSECT

Sometimes, instead of finding new jobs, we want to find jobs that are common to
two different days.

Query

DAX Query
EVALUATE
    INTERSECT(
        SELECTCOLUMNS('Jan-04', 
            "Title", 'Jan-04'[Title],
            "Location", 'Jan-04'[Location],
            "Company", 'Jan-04'[Company],
            "Skill", 'Jan-04'[Skills]
        ),
        SELECTCOLUMNS('Jan-03', 
            "Title", 'Jan-03'[Title],
            "Location", 'Jan-03'[Location],
            "Company", 'Jan-03'[Company],
            "Skill", 'Jan-03'[Skills]
        )
    )

Step-by-step explanation

Step 1: Prepare Jan-04
SELECTCOLUMNS extracts Title, Location, Company, and Skill from
the Jan-04 table.

Step 2: Prepare Jan-03
The second SELECTCOLUMNS creates the same structure from Jan-03.

Step 3: INTERSECT
INTERSECT returns the rows that are common to both table expressions.
In this query, it identifies job records that appear in both Jan-04 and Jan-03
based on the selected columns.

Key takeaway: INTERSECT(Table1, Table2) returns
the common set of rows from both table expressions. In this query, the comparison
is based on the four selected columns.

EXCEPT vs INTERSECT

Function Purpose Job Data Example
EXCEPT Returns rows in the first table that are not in the second table Jobs in Jan-04 but not in Jan-03
INTERSECT Returns rows common to both tables Jobs appearing in both Jan-04 and Jan-03

4. Combining Tables Using UNION

What if we want to combine the job listings from two different days into one result?
This is where UNION becomes useful.

Query

DAX Query
EVALUATE
    UNION(
        SELECTCOLUMNS('Jan-04', 
            "Title", 'Jan-04'[Title],
            "Location", 'Jan-04'[Location],
            "Company", 'Jan-04'[Company],
            "Skill", 'Jan-04'[Skills]
        ),
        SELECTCOLUMNS('Jan-03', 
            "Title", 'Jan-03'[Title],
            "Location", 'Jan-03'[Location],
            "Company", 'Jan-03'[Company],
            "Skill", 'Jan-03'[Skills]
        )
    )

Step-by-step explanation

Step 1: Prepare Jan-04
The first SELECTCOLUMNS creates a four-column table from Jan-04.

Step 2: Prepare Jan-03
The second SELECTCOLUMNS creates the same four-column structure
from Jan-03.

Step 3: UNION
UNION combines the rows from the first table expression with the
rows from the second table expression.

In this example, the job rows from Jan-04 and Jan-03 are returned together.
If the same row appears in both source tables, it can appear more than once in
the UNION result.

Key takeaway: UNION combines table expressions
vertically by adding the rows from one table to the rows of another table.
Duplicate rows are retained.

EXCEPT, INTERSECT and UNION at a glance

Function What it does
EXCEPT Returns rows from the first table that are not found in the second table
INTERSECT Returns common rows from both table expressions
UNION Combines rows from both table expressions and retains duplicates

5. Counting Jobs in Each Day Using COUNTROWS

After comparing and combining daily job tables, another useful requirement is to
understand how many jobs were collected on each day.

Query

DAX Query
EVALUATE
    VAR JAN1 = COUNTROWS('Jan-01')
    VAR JAN2 = COUNTROWS('Jan-02')
    VAR JAN3 = COUNTROWS('Jan-03')
    VAR JAN4 = COUNTROWS('Jan-04')
    VAR JAN5 = COUNTROWS('Jan-05')

    RETURN
    ROW(
        "Jan 01", JAN1,
        "Jan 02", JAN2,
        "Jan 03", JAN3,
        "Jan 04", JAN4,
        "Jan 05", JAN5
    )

Step-by-step explanation

Step 1: COUNTROWS(‘Jan-01’)
COUNTROWS counts the number of rows in the Jan-01 table.
The result is stored in the variable JAN1.

Step 2: Repeat for the remaining days
The same pattern is used for Jan-02, Jan-03, Jan-04, and Jan-05.
Each count is stored in a separate variable.

Step 3: RETURN
The RETURN statement outputs the final table expression.

Step 4: ROW
ROW creates a single-row table containing the five daily job counts.
Each label such as “Jan 01” is used as an output column name.

What will you get?

The exact numbers depend on the data in your daily tables. The output structure will
look like this:

Jan 01 Jan 02 Jan 03 Jan 04 Jan 05
Job Count Job Count Job Count Job Count Job Count
Key takeaway: COUNTROWS(Table) returns the
number of rows in the specified table or table expression.

Understanding the Complete Query Pattern

This example demonstrates an important pattern for working with multiple daily
datasets in DAX. First, we shape the data using SELECTCOLUMNS.
Then, we use set functions to compare or combine those table expressions.

Requirement DAX Function Purpose
Identify jobs that appeared on Jan-04 but not Jan-03 EXCEPT Find rows unique to the first table
Find jobs appearing on both days INTERSECT Find common rows
Combine job listings from two days UNION Append rows from both tables
Count jobs collected on each day COUNTROWS Count rows in each daily table

📝 Practice Exercise

Using the same job dataset, try creating the following DAX queries:

  1. Find jobs that exist in Jan-05 but not in Jan-04.
  2. Find jobs common to Jan-05 and Jan-04.
  3. Combine the job listings from Jan-01 and Jan-05.
  4. Count the number of jobs available in each daily table.

For the comparison queries, use Title, Location,
Company, and Skills as the job-identifying columns.

Conclusion

In this article, we learned how DAX table functions can be used to compare,
combine, and analyze daily job datasets.

  • EXCEPT returns rows from the first table that are not present in the second table.
  • INTERSECT returns rows common to both table expressions.
  • UNION combines rows from multiple table expressions while retaining duplicates.
  • SELECTCOLUMNS helps create matching table structures before comparison or combination.
  • COUNTROWS counts the number of rows in a table or table expression.
  • ROW can be used to present multiple calculated values as a single-row result.

These functions are particularly useful when working with repeated datasets,
daily snapshots, job listings, sales extracts, and other scenarios where
comparing or combining tables is required.

Next: Continue exploring DAX table functions and learn how
functions such as FILTER, ADDCOLUMNS,
SUMMARIZE, and SELECTCOLUMNS can be combined
to build more powerful analytical queries.


📥 Practice Data:
Download Practice Data Free

🎥 Prefer learning through video?
DAX YouTube Playlist