Using the connector with your BI tool

The Fuse BI Connector is a read-only Amazon Redshift database. Anything that can talk to Redshift — or to PostgreSQL, since Redshift speaks a dialect of it — can build on it. This page covers what you need regardless of tool, then the specifics for the common ones.

Connecting

Your Fuse contact provides the endpoint, port, database name, schema and read-only credentials. Most tools connect one of three ways:

Method

When to use it

Notes

Native Redshift connector

First choice wherever the tool offers one

Best performance and type handling. Available in Power BI, Tableau, Looker, Qlik, Sigma and most modern tools.

PostgreSQL connector

Where there is no Redshift option

Works because Redshift is Postgres-derived. Some functions and type mappings differ, so test date and numeric columns carefully.

JDBC / ODBC driver

Java or desktop tools, Excel, bespoke applications

Download the current driver from AWS. Keep it updated — older drivers handle newer Redshift types poorly.

Two things to sort out before you start building. First, SSL should be enabled on the connection — check your tool defaults to it rather than assuming. Second, your organisation's outbound IP range may need allow-listing before the connection will open at all; if the connection times out rather than rejecting your credentials, that is usually why. Raise both with your Fuse contact.

Live query or extract?

Every tool offers some version of this choice, under different names — Import vs DirectQuery, Extract vs Live, cached vs direct.


Extract / import

Live / direct query

Best for

Dashboards people use daily

Ad-hoc exploration, very large tables you do not want to copy

Speed for the reader

Fast — data sits in the tool

Depends on Redshift and network each time

Freshness

As of the last refresh

Current

Load on Redshift

Concentrated at refresh time

Every interaction issues a query

For most Fuse reporting, extracts refreshed nightly are the right default. The underlying data does not change second by second, and dashboards will be far more responsive. Use live query for the engagement tables only if you genuinely need same-day figures and can accept slower dashboards.

Patterns you will need to translate

These are the modelling problems the Fuse schema will hand you. The problem is the same in every tool; only the syntax changes. Each one can also be solved in SQL before the data reaches your tool, which is often the simplest answer.

1. Polymorphic joins — filter before you join

Several tables reference "any kind of object" through an ID column plus a type column: views.viewable_id + viewable_type, shares.shareable_id + shareable_type, likes.likable_id + type, learning_plan_items.item_id + item_type, and others.

The problem: no BI tool can define a relationship that changes its target depending on a column value.

The fix, in any tool: create one filtered query per type. A "Content views" query filtered to viewable_type = 'Content' joins cleanly to contents. A separate "Topic views" query filtered to viewable_type = 'Topic' joins to topics. Do the filtering in SQL if you can, so Redshift does the work and you move less data.

Do not join on the ID alone and hope. Content ID 500 and topic ID 500 are different objects, and the join will silently produce nonsense.

2. Pivoting custom profile fields

profile_values holds one row per user per field. To use department, region or job title as a filter, you need those as columns.

The cleanest fix is SQL, because it works identically everywhere:

SQL
SELECT
  pv.user_id,
  MAX(CASE WHEN pf.label = 'Department' THEN pv.value END) AS department,
  MAX(CASE WHEN pf.label = 'Region'     THEN pv.value END) AS region,
  MAX(CASE WHEN pf.label = 'Job Title'  THEN pv.value END) AS job_title
FROM profile_values pv
JOIN profile_fields pf ON pf.id = pv.profile_field_id
WHERE pf.deleted_at IS NULL
GROUP BY pv.user_id

Every tool also has its own pivot step if you prefer to do it there. Either way, respect profile_fields.exclude_from_reporting — fields flagged that way are deliberately kept out of analytics.

3. The manager hierarchy is a self-join

There is no manager_id column. A user's manager is another row in users, pointed at by users.owner_id.

The fix: bring users in twice — once as your people dimension, once aliased as "Managers" — and join users.owner_id to managers.id. In SQL that is a straightforward self-join. In a visual modelling tool you will usually need a second copy of the table, because most tools refuse a direct self-relationship.

If you need more than one level of hierarchy (manager's manager), do it in SQL with repeated joins. Recursive hierarchy support varies a lot between tools and is rarely worth fighting.

4. Engagement lives across five tables

There is no single engagement fact table. Views, likes, comments, shares and follows are separate, and Universal Analytics adds them together.

The fix: union the five into one fact table with an added column naming the engagement type. That gives you a single date axis, a single user join, and an engagement-type filter for free — and it performs better than five separate joins.

SQL
SELECT id, user_id, created_at, 'view' AS engagement_type FROM views
UNION ALL
SELECT id, user_id, created_at, 'like'    FROM likes
UNION ALL
SELECT id, user_id, created_at, 'comment' FROM comments WHERE deleted_at IS NULL
UNION ALL
SELECT id, user_id, created_at, 'share'   FROM shares
UNION ALL
SELECT id, user_id, created_at, 'follow'  FROM follows WHERE deleted_at IS NULL

Add the object ID and type columns to each branch if you need to slice by what was engaged with.

5. Build your own date table

The connector has no date dimension. Every serious BI tool needs one for period comparisons, running totals and fiscal calendars to behave.

The fix: generate a date table covering your full reporting range, mark it as your date dimension in whatever way your tool requires, and join it to created_at on your fact tables. Include fiscal year and quarter columns if your organisation does not run on the calendar year — retrofitting that later is painful.

6. Guard your divisions

Many of the useful Fuse figures are ratios, and several denominators can legitimately be zero or null. event_occurrences.spaces_number is null for uncapped events. A learning plan with no assignments has an audience of zero.

The fix: use your tool's safe-division function rather than a bare /, and decide deliberately whether a zero denominator should show as blank or as zero. Blank is usually more honest — it says "not applicable" rather than "nothing happened".

7. Distinct users versus row counts

This is the single most common cause of numbers that do not tie. A user in five communities produces five rows in memberships. A content item in three communities gets its views attributed three times if you join through community_items carelessly.

The fix: be explicit every time about whether you are counting people or events. Use a distinct count on user_id when you mean people. When a join fans out, aggregate before joining rather than after.

Notes for specific tools

Tool

What to know

Power BI

Native Redshift connector. Do the polymorphic filtering and profile pivot in Power Query. For the manager hierarchy, duplicate the users query and create an inactive relationship on owner_id, activating it with USERELATIONSHIP in your manager measures. Mark your date table with Mark as Date Table. Use DIVIDE() rather than /. Set up incremental refresh on views — it is by far the largest table.

Tableau

Native Redshift connector. Use Custom SQL for the polymorphic filters and the profile pivot rather than fighting the relationship model. Extracts with incremental refresh keyed on created_at work well for views. Watch relationship cardinality on the join tables (memberships, community_items) — Tableau's default relationships handle fan-out better than blends, but you still need to be deliberate about it. Use ZN() and explicit null handling on ratios.

Looker / Looker Studio

In Looker, model the polymorphic joins as separate views with sql_where on the type column, which is a clean fit for LookML. Define count_distinct measures on user_id explicitly so nobody accidentally counts rows. Persistent derived tables are a good home for the profile pivot and the engagement union. Looker Studio is more limited — do the joins in SQL and give it a flat result.

Qlik Sense

Qlik's associative model joins on identical field names, which is dangerous here — id exists on every table and type on several. Rename fields explicitly in your load script (users.id AS user_id) or Qlik will create associations you did not intend. Do the polymorphic filtering in the load script. QVDs are a good fit for the large engagement tables.

Metabase

Connect via the Redshift or Postgres driver. Save the polymorphic filters, engagement union and profile pivot as SQL-based Models so the questions people build on top are already correct. Set the semantic types on key columns so Metabase's automatic summarisation behaves.

Sigma / Omni / Hex

These query Redshift live. Push the joins and filters down into SQL or the tool's dataset layer once, then let people explore on top of that. Because everything runs live, be more careful than usual about scanning views unfiltered — always constrain by date.

Excel or Google Sheets

Fine for a one-off extract, not for a recurring dashboard. Use ODBC from Excel, or export from a SQL client for Sheets. Aggregate in SQL first — the engagement tables will exceed row limits quickly.

SQL client / data warehouse pipeline

If you are loading Fuse data into your own warehouse, model the polymorphic tables as separate typed tables at load time, and materialise the engagement union and profile pivot as views. Everything downstream then gets a clean model for free.

Redshift specifics worth knowing

Column names are lowercase

Redshift folds unquoted identifiers to lowercase. Reference columns in lowercase, and if you quote them, quote them in lowercase.

Several column names are reserved words

The Fuse schema uses type, value, status, position, group, role and state as column names. group in particular (on question_sets) will break a query if you do not quote it:

SQL
SELECT "group", position FROM question_sets;

Some tools quote everything automatically; some do not. If a query fails with a syntax error near an innocuous-looking column, this is usually why.

Timestamps are UTC

All created_at, updated_at, starts_at and similar columns are UTC. Convert to local time before grouping by day, or your daily figures will be shifted — and for organisations spanning time zones, decide once which zone your reporting uses and apply it consistently. Peak-hour analysis is meaningless without this.

Filter early, aggregate in SQL

Redshift is columnar and fast at aggregation, and moving fewer rows into your BI tool beats moving more. Select only the columns you need rather than everything, constrain by date range, and let Redshift do the grouping wherever the tool allows it. Exclude user_scorm_reporting_data.suspend_data from any import — it is a large opaque blob with no reporting value.

Sizing expectations

views is normally the largest table by a wide margin, followed by gamification_activities and the other engagement tables. Plan your refresh strategy around views specifically; everything else is comparatively small.

A sensible build order

  1. Connect and confirm you can read a small table such as communities.

  2. Build your date table.

  3. Bring in users, plus the profile pivot, as your people dimension.

  4. Add the dimension tables you need — communities, contents, topics.

  5. Add one fact table and get a single number to tie against the Universal Analytics dashboard before you build anything else.

  6. Only then add the remaining facts.

Reconciling one number early is much cheaper than reconciling twenty at the end.