Use case
Some datasets are spread across more than one database. Product events, for example, are often split by age: the last few months stay in a fast analytical database that serves live dashboards, while everything older is moved to cheaper storage. Both tables describe the same events and carry the same columns. The goal is to report on them together — one result set with the rows of both databases appended, plus a dimension that says which database each row came from. This is a union: it adds rows. It is a different problem from arollup_join, which
adds columns by relating entities that live in different databases. It is also
different from data blending,
which unions cubes inside a single database.
The SQL API can do this at query time,
against live data and without pre-aggregations. Each cube is queried on its own
data source, and Cube appends the results.
Configuration
Define the two connections as multiple data sources. The default source needs no name; every other source gets one, and the full list goes inCUBEJS_DATASOURCES:
Data modeling
Model each table as its own cube, and point one of them at the named data source withdata_source. The cube without
a data_source uses the default one.
Give both cubes a matching set of members, and add a constant dimension that
identifies the origin of each row. That dimension is what makes the two halves
of the union distinguishable once they sit in the same result set:
Querying
Connect to the SQL API and append the two cubes withUNION ALL:
WHERE clause on either side limits
what that database scans:
A cube whose name starts with
pg_ cannot be referenced by that name alone. The
SQL API routes such a name to pg_catalog, where no cube is ever found, and the
query fails with Table or CTE with name 'pg_...' not found. Qualify it with the
schema that holds cubes, as in FROM public.pg_costs, or avoid the prefix.Aggregating across the union
Wrap the union in a CTE to aggregate over both databases at once. Here the per-tier totals combine events from both databases:UNION also works where duplicate rows should collapse, as do an outer
ORDER BY and LIMIT over the union.
Inspecting how a query is split
RunEXPLAIN on any of these queries to see the plan. It puts a Union over one
CubeScan per cube, and each scan carries its own filter — the WHERE clause is
part of the request sent for that cube, not a step applied after the results are
appended:
data_source of each cube to see which database serves which half.
Limitations
Unions combine rows across data sources; joins do not. A query that joins two cubes on different data sources is rejected, and relating entities across databases needs arollup_join instead.
Each half of the union is subject to the maximum row
limit on its own, and the
cap applies before the results are appended. Aggregate inside each half of the
union, as in the examples above, rather than unioning raw rows and aggregating
afterwards.