SQL is great for querying data, but it does not produce charts on its own. The standard workflow is query then visualise: run a SQL query, extract the result columns, and pass them to a charting library.

In Python, this is what you do with pandas + matplotlib or Polars + matplotlib. In the browser, the equivalent is sql.js + Chart.js. The pattern is the same everywhere — SQL gives you the data, the charting library draws the picture.

This article walks through five interactive examples, starting with a raw data preview and building up to a fully styled grouped bar chart:

  1. Preview the dataset with SELECT *
  2. Simple bar chart — one series, one query
  3. Line chart with two series — EV vs diesel over time
  4. Polished chart — title, legend, axis labels, and grid styling
  5. Grouped bar chart with a computed column

The dataset

We will use a small dataset of UK car registrations comparing electric vehicles (EV) and diesel vehicles from 2018 to 2023. Each row records the year, the number of new EV registrations (ev_count), and the number of new diesel registrations (diesel_count).

Click Run on the first block to create the table and see the data:

SQL — editable
Figure 1: EV vs diesel registrations — 6 rows, 3 columns.

The numbers tell a dramatic story: EV registrations grew from 2,216 in 2018 to 87,217 in 2023, while diesel fell from 58,456 to 24,590. But numbers in a table are hard to read at a glance — a chart makes the trend instantly visible.

How the data flows from SQL to Chart.js

Each chart block below has two editors: a SQL editor on top and a Chart.js editor below it. When you click Run & Plot, the SQL query executes first and the result columns are automatically passed to the Chart.js code as variables:

This means the Chart.js code never contains hardcoded data. If you change the SQL query — add a WHERE, swap columns, or query a different table — the same Chart.js code adapts automatically because columns[0], columns[1], etc. always reflect whatever the query returned.

A simple bar chart

The first step is to query the data you want to plot. For a bar chart of EV registrations by year, all you need is:

SQL + Chart — editable
Chart.js — editable
Figure 2: EV registrations as a bar chart — the growth from 2021 onwards is immediately clear.

The ORDER BY year is important. Without it, SQL does not guarantee the row order, and your chart labels could appear shuffled. Always sort time-series data before plotting.

The pattern is simple: the first column becomes the x-axis labels, and the second column becomes the bar heights. Chart.js handles the rendering — you just pass the arrays.

A line chart with two series

To compare EV and diesel trends on the same chart, query both columns and render them as two lines:

SQL + Chart — editable
Chart.js — editable
Figure 3: Two lines — EV registrations rising, diesel registrations falling.

Each numeric column after the first becomes a separate line. The crossover point around 2022 is immediately visible on the chart but would be easy to miss in a table.

This is the power of the query-then-visualise pattern: SQL handles the data preparation (filtering, sorting, computing), and the chart library handles the presentation.

Polishing the chart

The default Chart.js output works, but real-world charts need a title, axis labels, a legend, and grid styling. The SQL query stays the same — all the polish happens in the Chart.js configuration:

SQL + Chart — editable
Chart.js — editable
Figure 4: Same data, polished — title, axis labels, legend, and styled grid lines.

In Python, this is equivalent to calling ax.set_title(), ax.set_xlabel(), and ax.legend() in matplotlib. In Polars or pandas, you would pass these as keyword arguments to the plot method. The concept is the same — only the syntax changes.

Grouped bar chart with a computed column

SQL can compute derived values before charting. Here we add a total column using arithmetic in the SELECT:

SQL + Chart — editable
Chart.js — editable
Figure 5: Grouped bar chart — EV, diesel, and total registrations side by side.

Computing the total in SQL rather than JavaScript keeps the logic in one place. This is a best practice: let SQL do the data work, and let the chart library do the drawing.

SQL vs Python: the query-then-visualise pattern

The pattern demonstrated here — query then visualise — is universal. The tools change, but the workflow is the same:

The advantage of doing it in the browser with sql.js and Chart.js is that there is nothing to install — the entire pipeline runs in a single HTML page. For production dashboards, you would typically use a BI tool or a Python script, but the underlying pattern remains the same.

Try editing the queries above — change ev_count to diesel_count, add a WHERE year >= 2020 filter, or compute a percentage column. The charts will update to reflect your new query.

References

Suhith Illesinghe
Curiosity is the first step to make a difference. I hope to inspire others to explore, build and champion collaborative growth.