Skip to main content
JupySQL is a Python library that lets you run SQL in Jupyter notebooks and the IPython shell. In this guide, we’re going to learn how to query data using chDB and JupySQL.

Setup

Let’s first create a virtual environment:
And then, we’ll install JupySQL, IPython, and Jupyter Lab:
We can use JupySQL in IPython, which we can launch by running:
Or in Jupyter Lab, by running:
If you’re using Jupyter Lab, you’ll need to create a notebook before following the rest of the guide.

Downloading a dataset

We’re going to use the New York City taxi dataset, which contains around 3 million taxi rides along with the fare, tip, and pickup neighborhood of each one. The trips are split across several TSV files, so let’s start by downloading those:

Configuring chDB and JupySQL

Next, let’s import the dbapi module for chDB:
And we’ll create a chDB connection. Any data that we persist will be saved to the taxi.chdb directory:
Let’s now load the sql magic and create a connection to chDB:
Next, we’ll display the display limit so that results of queries won’t be truncated:

Querying data in TSV files

We’ve downloaded a bunch of files with the trips_ prefix. Let’s use the DESCRIBE clause to understand the schema:
We can also write a SELECT query directly against these files to see what the data looks like:
If we look back at the schema, a few of the money-related columns — trip_distance, fare_amount, and tip_amount — were inferred as String rather than a numeric type. We’ll clean those up when we import the data into a table.

Importing TSV files into chDB

Now we’re going to store the data from these TSV files in a table. The default database doesn’t persist data on disk, so we need to create another database first:
And now we’re going to create a table called trips whose schema will be derived from the structure of the data in the TSV files. We’ll use the REPLACE clause to cast the money-related columns to Float64, and the transform function to turn the numeric pickup_borocode column into a human-readable borough name:
Let’s do a quick check on the data in our table:
Just over 3 million trips — let’s also bring in a second table. New York City’s Taxi & Limousine Commission divides the city into taxi zones, and a lookup file maps each zone to its borough. Let’s download that file:
And then create a table called zones based on the content of the CSV file:
Once that’s finished running, we can have a look at the data we’ve ingested:

Querying chDB

Data ingestion is done, now it’s time for the fun part - querying the data! Each borough is divided into a different number of taxi zones. We’re going to write a query that joins the two tables to find out how many trips were picked up in each borough, and how many trips that works out to per taxi zone:
Manhattan and Queens have the same number of taxi zones, but Manhattan generates over 14 times as many pickups.

Saving queries

We can save queries using the --save parameter on the same line as the %%sql magic. The --no-execute parameter means that query execution will be skipped.
When we run a saved query it will be converted into a Common Table Expression (CTE) before executing. In the following query we compute the neighborhoods with the highest average tip:
The top entries are neighborhoods with only a handful of trips, so a single generous ride skews the average. Let’s filter those out.

Querying with parameters

We can also use parameters in our queries. Parameters are just normal variables:
And then we can use the {{variable}} syntax in our query. The following query finds the neighborhoods with the highest average tip among those with more than 10,000 trips:
Airport pickups tip the most by a wide margin — those long rides into the city add up.

Plotting histograms

JupySQL also has limited charting functionality. We can create box plots or histograms. We’re going to create a histogram, but first let’s write (and save) a query that returns the distance of each trip under 20 miles. We’ll be able to use this to create a histogram that counts how many trips fall into each distance bucket:
We can then create a histogram by running the following:
Most trips are short hops of one to three miles, with a long tail stretching out towards the airport runs.
Last modified on July 27, 2026