Skip to content

Getting the numbers right

The short list of things about this data that produce plausible-looking wrong numbers. Everything here has been the cause of a real reporting error.

If you read one page before publishing a figure, read this one.

1. Never sum across currencies

The data holds several currencies in one column — EUR, USD, CHF, QAR, and null.

A SUM(TicketGrossPrice) without grouping by CurrencyShort produces a number with no meaning whatsoever, and nothing in the output will tell you it is wrong.

Include CurrencyShort in the grouping of every monetary question, and label each figure with its currency. Default to TicketGrossPrice; use TicketNetPrice only when net was explicitly asked for.

2. Exclude test sales

Test sales exist in production data. They are created during configuration and rehearsal, and they look exactly like real ones except for a flag.

Filter SaleIsTest eq false unless the question is specifically about test data. Do this in the extract, not in each report, so nobody downstream can forget it.

3. Not every row in Tickets is a ticket

ArticleType also covers vouchers, catalogues, service fees and functional features. A count of rows is a count of sold items, not of admissions.

Filter ArticleType eq 'TICKET' whenever you mean tickets. See Datasets → Column values.

4. The FKM flags are independent, not a partition

IsFkmTotal and IsFkmVisitor on StatisticGroups are independent. A group can carry both, one, or neither, and a group with both false is a perfectly normal business category.

Never compute "non-visitors" as total minus visitor. The subtraction is meaningless and the result looks entirely credible. Report the two figures separately.

5. Joins that multiply

TicketsTicketUsages and TicketsStatisticGroups are both one-to-many. A count taken after joining counts the wrong thing.

This bites hardest on attendance by statistics group: an article in three groups produces three rows per ticket. Count distinct TicketInternalId, not rows.

And an article with no statistics group has no row at all, so an inner join silently drops those tickets. Left join, and give the unassigned bucket a deliberate meaning.

6. Match events exactly, and filter the year separately

?$filter=FaireventName eq 'Trade Fair' and FaireventYear eq 2026

contains silently merges similarly named events. Folding the year into the name silently misses editions.

7. Do not mix organiser and exhibitor tickets

Exhibitor invitations are typically free, issued in bulk, and redeemed at a much lower rate. Averaged together with organiser sales they drag down every conversion figure and describe neither group.

8. Buyer and holder are different people

"Bought" is a Buyer* question. "Attended" is a TicketOwner* question. When a stakeholder's question is ambiguous, answer both.

9. Scans are not visitors

You wantCount
Visitsrows in TicketUsages
People who camedistinct TicketInternalId
Daily unique attendancedistinct tickets with IsFirstOfDay eq true
Arrivals onlyfilter IsEntry eq true

And a ticket never scanned has no row there at all — use a left join from Tickets when measuring no-shows.

10. Survey rows are selections, not responses

One multi-select answer produces one row per ticked box. Count distinct SubmissionInternalId for responses and distinct AnswerInternalId for answers.

11. Free is not unpaid

SalePaymentStatus eq 'NOT_REQUIRED' means the ticket was free by design. NOT_PAID means money is outstanding. Treating them alike either invents debt or hides it.

12. Two tokens mean approved

LegitimationStatus has both ACCEPTED and AUTO_APPROVED. Any approval rate that counts only one of them is wrong.

13. Nulls are not false

A nullable boolean can be null, and eq false does not match it. Where a flag is nullable, decide explicitly what null means in your report.

14. Do not time-zone convert dates

TicketOwnerBirthDate is a calendar date. Converting it shifts birthdays and corrupts age brackets. See Datasets → Reading the columns.

When you publish

State the filters you applied, including the defaults — the test-sale exclusion in particular. A figure whose filters are undisclosed cannot be checked, and audited attendance figures need to be checkable.