Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I count distinct values within each group?

Quick answer

Group rows by the value that identifies each group, then apply COUNT(DISTINCT value_column) to count unique, non-NULL values in each group. For example, GROUP BY event_id with COUNT(DISTINCT attendee_id) counts each attendee once per event. COUNT(*) gives a different result: it counts every row in the group, including rows where attendee_id is NULL. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have an event table with one row per attendee check-in, but some attendees appear more than once at an event. How do I get the number of distinct attendees for each event?

Geez

Group by the event’s identifier and count distinct attendee IDs. In SQLite, the query is:

SELECT event_id,
       COUNT(DISTINCT attendee_id) AS distinct_attendees
FROM event_checkins
GROUP BY event_id
ORDER BY event_id;

GROUP BY event_id makes a group of rows for each event. COUNT(DISTINCT attendee_id) counts each different, non-NULL attendee ID once within that group. [S1]

For a made-up example, assume the table contains these rows:

event_id | attendee_id
---------|------------
101      | A7
101      | A7
101      | B2
101      | NULL
202      | C4
202      | C4
202      | D9

The query returns:

event_id | distinct_attendees
---------|-------------------
101      | 2
202      | 2

At event 101, A7 appears twice but contributes one distinct ID; B2 contributes another. The NULL attendee ID is not counted. These results illustrate the query using only the assumed sample rows, not a claim about any actual event data.

Follow-up question

Why not just use COUNT(*)? I want to understand exactly what changes when there are duplicate check-ins.

Geez

COUNT(*) counts every row in each group, so it includes duplicate check-ins and rows with a NULL attendee ID. COUNT(DISTINCT attendee_id) instead removes duplicate attendee-ID values for the count and does not count NULL attendee IDs. [S1]

For the assumed sample, adding COUNT(*) alongside the distinct count makes the difference visible:

SELECT event_id,
       COUNT(*) AS checkin_rows,
       COUNT(DISTINCT attendee_id) AS distinct_attendees
FROM event_checkins
GROUP BY event_id
ORDER BY event_id;
event_id | checkin_rows | distinct_attendees
---------|--------------|-------------------
101      | 4            | 2
202      | 3            | 2

These columns answer different questions: the first counts records in the group; the second counts unique non-NULL attendee IDs. Choose based on what the number is meant to represent.

Follow-up question

What if my report should show an event name instead of an ID, or I need to count a different field?

Geez

Use the column that identifies the group in both the selected output and GROUP BY, and put the value you want to deduplicate inside COUNT(DISTINCT ...). For example, if your table has an event_name column and each name identifies one event, you could write:

SELECT event_name,
       COUNT(DISTINCT attendee_id) AS distinct_attendees
FROM event_checkins
GROUP BY event_name
ORDER BY event_name;

For a different distinct count, replace attendee_id with the relevant column. For example, counting unique ticket codes per event would use COUNT(DISTINCT ticket_code) while still grouping by event_id.

Choose the grouping column with care: if separate events can share a name, grouping only by name combines their rows. In that case, group by the event ID to keep those events separate, and include a name in the output only if your query and data design support that choice. The example assumes the column names exist; adapt them to your schema.

Follow-up question

How can I check that I have grouped and counted the right thing before using the result?

Geez

First, confirm what one output row should represent—for example, one event ID—and what value should be unique—for example, one attendee ID within that event. Then inspect a small set of source rows that includes a duplicate and, if relevant, a NULL. Compare the query’s distinct count with the unique non-NULL values visible in each group.

A useful review is to run both COUNT(*) and COUNT(DISTINCT attendee_id) temporarily, as in the earlier example. If they match, that does not by itself prove the grouping is correct; it only shows the two counts are equal for those rows. Check that the selected grouping key keeps separate groups separate, and verify that excluding NULL IDs is appropriate for your intended definition of an attendee.

SQLite’s documented distinction establishes how these aggregate counts treat rows and values. It does not establish that your chosen columns correctly represent events or attendees; that depends on your table’s meaning and data.

A practical checklist

  • Decide what one result row represents, such as one event.

  • Group by the column that identifies that entity, such as event_id.

  • Use COUNT(DISTINCT value_column) for unique, non-NULL values within each group.

  • Check how NULL values should be treated; this count excludes them.

  • Compare COUNT(*) and the distinct count on sample rows containing duplicates.

  • Confirm that the grouping key does not combine separate entities unintentionally.

A few more useful answers

Does COUNT(DISTINCT attendee_id) count NULL attendee IDs?

No. In SQLite, COUNT(DISTINCT X) counts distinct non-NULL values of X, so NULL attendee IDs are excluded. [S1]

What does COUNT(*) count when I use GROUP BY?

It counts all rows in each group, including rows with duplicate values or NULLs in the attendee column. [S1]

Can I count distinct values for a different column?

Yes. Replace attendee_id with the column whose distinct, non-NULL values you want to count, while keeping the grouping column that defines each result row.

Sources

References used for this guide.

  1. [S1] SQLite built-in aggregate functions: COUNT and DISTINCT
    sqlite.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work