Three visitors on the first day, three on the second, two on the third. Eight people? Only if nobody returned. In our sample, several did: the three days contain five distinct visitor IDs.
We will calculate the exact answer first, then build daily sketches that can be combined later. The key idea is preserving enough information about overlap to estimate a union, instead of adding incompatible counts.
Explore the idea
Returning visitors do not become new people
Add another day and follow which IDs are actually new to the period.
6 ≠ 4
daily counts versus period distinct IDs
Six daily memberships belong to four IDs
Ben and Cy appear on both days. The union contains Ada, Ben, Cy, and Dee.
8 ≠ 5
daily counts versus period distinct IDs
Ada returns; Eli is the new ID
Adding two daily visitors increases the period’s distinct count by only one. The diagram shows exact sets; the SQL below introduces approximate sketches.
The events, including repeat visits
Names stand in for stable, fictional visitor IDs. We are counting distinct IDs, not proving how many individual humans visited. Identity changes and shared IDs are separate tracking problems.
events9 rows
Three days of repeat visitors
Names are fictional stable visitor IDs. There are nine events, eight daily memberships, and five distinct IDs.
| id | day | visitor_id |
|---|---|---|
| 1 | 2026-01-01 | Ada |
| 2 | 2026-01-01 | Ben |
| 3 | 2026-01-01 | Cy |
| 4 | 2026-01-01 | Ada |
| 5 | 2026-01-02 | Ben |
| 6 | 2026-01-02 | Cy |
| 7 | 2026-01-02 | Dee |
| 8 | 2026-01-03 | Ada |
| 9 | 2026-01-03 | Eli |
Ada appears twice on the first day. A distinct count within that day handles the repeated event correctly:
Count distinct IDs within each day
SELECT day::VARCHAR AS day, count(DISTINCT visitor_id) AS unique_visitors
FROM events GROUP BY day ORDER BY day;
| day | unique_visitors |
|---|---|
| 2026-01-01 | 3 |
| 2026-01-02 | 3 |
| 2026-01-03 | 2 |
But the daily counts have discarded which IDs overlapped. Ben and Cy appear on both January 1 and 2; Ada returns on January 3.
Establish the exact answer
Compare the sum of daily counts with an exact distinct count over the entire period:
Compare adding counts with counting the union
WITH daily AS (SELECT day, count(DISTINCT visitor_id) AS n FROM events GROUP BY day)
SELECT (SELECT sum(n) FROM daily) AS sum_of_daily_counts,
(SELECT count(DISTINCT visitor_id) FROM events) AS period_unique_visitors;
| sum_of_daily_counts | period_unique_visitors |
|---|---|
| 8 | 5 |
Eight daily memberships belong to five distinct IDs. SUM is appropriate for additive measures such as event counts. A distinct count is not additive across overlapping groups.
If your raw data is available and an exact COUNT(DISTINCT visitor_id) meets your needs, use it. This tiny example does not need approximation. It exists to make the overlap visible before we introduce a technique for storing compact, mergeable summaries.
Store a daily sketch, then merge it
Query.Farm’s DataSketches extension can build an HLL sketch from IDs and estimate the distinct count represented by it. The setup creates daily_sketches with one datasketch_hll(12, visitor_id) value per day. The 12 controls sketch size and accuracy; it is not a requested number of visitors.
Merge those saved sketches, then ask for an estimate:
Estimate the union from saved daily sketches
SELECT round(datasketch_hll_estimate(
datasketch_hll_union(12, sketch)
), 2) AS estimated_visitors
FROM daily_sketches;
| estimated_visitors |
|---|
| 5 |
The merge operates on sketch state, not on the displayed daily estimates. An estimate alone has lost the information needed for a union. That is the useful distinction between saving a count and saving a mergeable sketch.
Our result rounds to 5.00, matching the exact answer. That agreement on five IDs is not an accuracy guarantee. Sketches are approximate; larger inputs can produce estimates above or below the exact count. Rounding improves presentation, not accuracy.
Keep the sketch family, ID representation, and configuration consistent across partitions. Test the chosen settings against exact counts on representative samples before deciding the error is acceptable.
Choose a smaller reporting window
Because each daily sketch is stored separately, we can select the days we need and combine only those summaries. The first two days contain four distinct IDs even though their daily counts sum to six.
Your turn · check your answer
Combine just the first two days
Return estimated_visitors for January 1–2 using the stored daily sketches. Round the estimate to two decimal places.
See the expected result
| estimated_visitors |
|---|
| 4 |
Preparing the editor…
Your result
Need a hint?
Filter the daily sketch rows before merging them. Adding daily counts counts Ben and Cy twice.
Show a solution
SELECT round(datasketch_hll_estimate(
datasketch_hll_union(12, sketch)
), 2) AS estimated_visitors
FROM daily_sketches
WHERE day <= DATE '2026-01-02';For a real week, define its date boundary and time zone before assigning events to days. These fixtures already contain dates, so no time-zone conversion is hidden inside the example.
What this technique saves—and what it does not
Building a sketch still requires reading its input records. The reuse happens afterward: a rolling-period estimate can read the saved daily summaries instead of all the original events. Measure that tradeoff on the size and update pattern you actually have.
Ordinary HLL union does not provide subtraction. If an older partition is corrected, rebuild or replace that partition’s sketch and recompute the requested union; do not subtract its previous estimate from a total. Preserve raw data according to the accuracy and correction requirements of your system.
Use exact aggregates when the result must be exact, including reconciliation of charges. Use mergeable sketches when compact reusable summaries and an understood approximation fit the question. For another common source of inflated metrics, try fixing totals after a join.