Rebuilding the dashboards against ClickHouse: seven datasets exercising uniqHLL12, quantileTDigest, sampling, window functions, and dictGet, then 18 charts across four dashboards.
This guide walks through the full manual setup of all ClickHouse datasets, charts, and dashboards in Superset. Follow this to understand what each visualization does and how it is built.
Want to skip ahead? Run the import script to have everything created automatically:
The script creates the connection, imports all 7 datasets, 18 charts, and 4 dashboards in one shot. Use this guide as a reference or to rebuild individual pieces.
Important — placeholder credentials in superset/dashboards/dashboard_export_*.zip.
The committed dashboard ZIP has its databases/*.yaml redacted to placeholders:
Auto-import (add_clickhouse_connection.sh) — works as-is. The script rewrites sqlalchemy_uri inside the ZIP using ${CLICKHOUSE_HOST} / ${CLICKHOUSE_USER} / ${CLICKHOUSE_PASSWORD} from your .envbefore posting to the import endpoint, so the placeholder host never reaches Superset.
Manual import via Superset UI — the imported database will be created with your-instance.clickhouse.cloud and won't connect. After import, go to Settings → Database Connections → Edit the entry and replace sqlalchemy_uri with your real ClickHouse Cloud URI (e.g. clickhousedb://default:<PASSWORD>@<your-host>.clickhouse.cloud:8443/analytics?secure=true).
Re-exporting your own dashboards — Superset bakes your real ClickHouse host into the export. Before committing, redact the host back to your-instance.clickhouse.cloud so your service identifier doesn't leak into git history.
Prerequisites: The analytics layer is populated (dbt run done in Step 7.3) and the dictionary exists (scripts/04_create_dictionary.sql done in Step 7.4).
Used by: Capabilities Showcase — demonstrates uniqHLL12() approximate counting vs exact uniq().
Go to Datasets → + Dataset.
Click Switch to SQL Lab (or select the Virtual tab).
Set Database = NYC Taxi — ClickHouse Cloud.
Paste SQL:
SELECT toDate(pickup_at) AS day, uniq(trip_id) AS exact_unique_trips, uniqHLL12(trip_id) AS approx_unique_trips, round( abs(uniq(trip_id) - uniqHLL12(trip_id)) / uniq(trip_id) * 100, 2 ) AS pct_errorFROM analytics.fact_trips FINALWHERE pickup_at >= today() - INTERVAL 30 DAYGROUP BY dayORDER BY day
Name it CH Approx Unique Trips (uniqHLL12) and click Save.
Used by: Capabilities Showcase — demonstrates window functions (AVG(...) OVER (...)) for rolling revenue by borough.
Go to Datasets → + Dataset → Virtual.
Set Database = NYC Taxi — ClickHouse Cloud.
Paste SQL:
SELECT week, pickup_borough, trips, revenue, round(avg(revenue) OVER ( PARTITION BY pickup_borough ORDER BY week ROWS BETWEEN 3 PRECEDING AND CURRENT ROW ), 2) AS rolling_4wk_avg_revenueFROM ( SELECT toStartOfWeek(pickup_at) AS week, pickup_borough, count() AS trips, round(sum(fare_amount_usd), 2) AS revenue FROM analytics.fact_trips FINAL GROUP BY week, pickup_borough)ORDER BY week DESC, revenue DESCLIMIT 100
Used by: Capabilities Showcase — demonstrates quantileTDigest() as a ClickHouse-native percentile function.
Go to Datasets → + Dataset → Virtual.
Set Database = NYC Taxi — ClickHouse Cloud.
Paste SQL:
SELECT vendor_name, quantileTDigest(0.5)(fare_amount_usd) AS p50_fare, quantileTDigest(0.95)(fare_amount_usd) AS p95_fare, quantileTDigest(0.99)(fare_amount_usd) AS p99_fare, count() AS trip_countFROM analytics.fact_trips FINALGROUP BY vendor_nameORDER BY vendor_name
Name it CH Fare Percentiles (quantileTDigest) and click Save.
Used by: Capabilities Showcase — demonstrates dictGet() for zero-JOIN dimension enrichment.
Requires: the dictionary analytics.taxi_zones_dict from Step 7.4 (scripts/04_create_dictionary.sql).
Go to Datasets → + Dataset → Virtual.
Set Database = NYC Taxi — ClickHouse Cloud.
Paste SQL:
SELECT dictGet('analytics.taxi_zones_dict', 'borough', toUInt16(pickup_location_id)) AS borough, dictGet('analytics.taxi_zones_dict', 'zone', toUInt16(pickup_location_id)) AS zone, count() AS trips, round(avg(fare_amount_usd), 2) AS avg_fareFROM default.trips_rawWHERE pickup_at >= today() - INTERVAL 7 DAYGROUP BY borough, zoneORDER BY trips DESC
Name it CH Zone Dict Lookup and click Save.
This dataset reads from default.trips_raw (raw table) rather than analytics.fact_trips to show the dictionary working at the source layer without any pre-processing.
After completing Part 3, open http://localhost:8088. Under Dashboards, you should see 7 total — 3 Snowflake dashboards (from Part 1 setup) and 4 prefixed CH —.
fact_trips or agg_hourly_zone_trips not found
Run dbt run first (Step 7.3).
dictGet returns empty strings
The analytics.taxi_zones_dict dictionary has not been created. Run scripts/04_create_dictionary.sql (Step 7.4).
Virtual dataset returns no rows
The 30-day / 7-day window in some queries requires recent data. If your migration data is all historical, replace the time filter with a fixed date:
-- Replace: WHERE pickup_at >= today() - INTERVAL 30 DAY-- With: WHERE pickup_at >= '2023-01-01'
403 error from the import script
Your Superset session cookie has expired. Log out and back in, then re-run.