The "DB::Exception: Expected ALL or DISTINCT" error in ClickHouse appears when you write a UNION statement without specifying whether duplicates should be kept (ALL) or removed (DISTINCT). Unlike some SQL dialects where bare UNION defaults to deduplication, ClickHouse requires the qualifier to be explicit. This error is identified by the code EXPECTED_ALL_OR_DISTINCT.
Impact
Any query containing a bare UNION without a qualifier will fail immediately. This commonly affects SQL migrations from systems like PostgreSQL or MySQL, where UNION alone is valid syntax that implicitly deduplicates rows.
Common Causes
- Writing
SELECT ... UNION SELECT ...without appendingALLorDISTINCT. - Migrating queries from another RDBMS that allows bare
UNION. - Using SQL generation tools or ORMs that emit standard SQL without ClickHouse-specific adjustments.
- Copy-pasting example queries from generic SQL tutorials.
Troubleshooting and Resolution Steps
Add the appropriate qualifier: Determine whether you need all rows (including duplicates) or only unique rows:
-- Keep all rows, including duplicates SELECT col1 FROM table1 UNION ALL SELECT col1 FROM table2; -- Remove duplicate rows SELECT col1 FROM table1 UNION DISTINCT SELECT col1 FROM table2;Default to UNION ALL when unsure: In most analytical workloads,
UNION ALLis the right choice. It is faster because it skips the deduplication step, and if your source queries already produce non-overlapping data, deduplication is unnecessary overhead.Update SQL generators: If the query is built by an ORM or code generator, configure it to emit
UNION ALLorUNION DISTINCTfor ClickHouse targets.Set the default mode: ClickHouse offers the
union_default_modesetting. You can set it to'ALL'or'DISTINCT'to allow bareUNIONstatements:SET union_default_mode = 'ALL'; SELECT col1 FROM table1 UNION SELECT col1 FROM table2; -- now treated as UNION ALLHowever, relying on this setting reduces query portability and clarity.
Apply the fix to INTERSECT and EXCEPT as well: The same qualifier requirement applies to
INTERSECTandEXCEPTin ClickHouse. If your query uses those set operations, addALLorDISTINCTto each one.
Best Practices
- Always write
UNION ALLorUNION DISTINCTexplicitly for clarity and portability. - Prefer
UNION ALLin analytical queries where performance matters and duplicates are acceptable or impossible. - If migrating a large SQL codebase, use a search-and-replace to find bare
UNIONkeywords and add the qualifier. - Avoid relying on
union_default_modein production queries; explicit qualifiers are clearer to future maintainers.
Frequently Asked Questions
Q: Why doesn't ClickHouse just default to UNION DISTINCT like standard SQL?
A: ClickHouse's design philosophy emphasizes explicit behavior. Since UNION ALL and UNION DISTINCT have very different performance characteristics — deduplication can be expensive on large datasets — the engine requires you to state your intent.
Q: Can I set union_default_mode globally for all sessions?
A: Yes, you can set it in the server configuration under user profiles or in users.xml. This makes bare UNION work for all queries under that profile, though explicit qualifiers are still recommended.
Q: Does this also apply to UNION inside subqueries and CTEs?
A: Yes. Every UNION in a query — whether at the top level, inside a subquery, or within a CTE — must have an ALL or DISTINCT qualifier unless union_default_mode is set.