SQL Examples: Basic SELECT Queries¶

This notebook contains simple SQL queries written for practice using the Chinook SQLite database.
I’m using it to demonstrate clear, well-structured query writing in a Jupyter environment.

The examples below cover:

  • Selecting and filtering data
  • Sorting and limiting results
  • Using basic expressions and aliases

Each query is executed through Python (sqlite + pandas), with outputs shown directly below for clarity.


Setup¶

In [1]:
from pathlib import Path
from IPython.display import Image, display
import pandas as pd

# project root
repo_root = Path().resolve().parent  

# database path relative to project root
DB_PATH = repo_root / "data" / "Chinook_Sqlite.sqlite"

assert DB_PATH.exists(), f"Database file not found: {DB_PATH}"

# SQLAlchemy engine
from sqlalchemy import create_engine
engine = create_engine(f"sqlite:///{DB_PATH}")

# image path relative to repo root
image_path = repo_root / "input" / "ChinookDBStructure.png"

# check it exists
assert image_path.exists(), f"Image file not found: {image_path}"

# display
display(Image(filename=str(image_path), width=600, height=400))
No description has been provided for this image

Query Examples¶

1) List all customers with their first and last names.¶

In [5]:
query = """

SELECT DISTINCT TRIM(FirstName || ' ' || LastName) as customer_name
FROM customer 
ORDER BY customer_name 
LIMIT 10 ;

"""
df = pd.read_sql_query(query, engine)
df
Out[5]:
customer_name
0 Aaron Mitchell
1 Alexandre Rocha
2 Astrid Gruber
3 Bjørn Hansen
4 Camille Bernard
5 Daan Peeters
6 Dan Miller
7 Diego Gutiérrez
8 Dominique Lefebvre
9 Eduardo Martins

2) Count how many invoices each customer has.¶

In [6]:
query = """

SELECT TRIM(c.FirstName || ' ' || c.LastName) AS customer_name,
       COUNT(i.InvoiceId) AS invoice_count
FROM customer AS c
JOIN invoice AS i ON c.CustomerId = i.CustomerId
GROUP BY c.CustomerId, c.FirstName, c.LastName
ORDER BY customer_name
LIMIT 10;

"""
df = pd.read_sql_query(query, engine)
df
Out[6]:
customer_name invoice_count
0 Aaron Mitchell 7
1 Alexandre Rocha 7
2 Astrid Gruber 7
3 Bjørn Hansen 7
4 Camille Bernard 7
5 Daan Peeters 7
6 Dan Miller 7
7 Diego Gutiérrez 7
8 Dominique Lefebvre 7
9 Eduardo Martins 7

3) Show the total revenue from all invoices.¶

In [5]:
query = """

SELECT SUM(Total) AS total_revenue
FROM invoice ;

"""
df = pd.read_sql_query(query, engine)
df
Out[5]:
total_revenue
0 2328.6

4) Find all tracks with a unit price greater than 0.99.¶

In [31]:
query = """

SELECT TrackId,
       Name,
       UnitPrice
FROM track
WHERE UnitPrice > 0.99

"""
df = pd.read_sql_query(query, engine)
df
Out[31]:
TrackId Name UnitPrice
0 2819 Battlestar Galactica: The Story So Far 1.99
1 2820 Occupation / Precipice 1.99
2 2821 Exodus, Pt. 1 1.99
3 2822 Exodus, Pt. 2 1.99
4 2823 Collaborators 1.99
... ... ... ...
208 3362 There's No Place Like Home, Pt. 1 1.99
209 3363 There's No Place Like Home, Pt. 2 1.99
210 3364 There's No Place Like Home, Pt. 3 1.99
211 3428 Branch Closing 1.99
212 3429 The Return 1.99

213 rows × 3 columns

5) List all unique genres in the database.¶

In [30]:
query = """

SELECT DISTINCT GenreId,
                Name AS Genre
FROM genre
ORDER BY Genre

"""
df = pd.read_sql_query(query, engine)
df
Out[30]:
GenreId Genre
0 23 Alternative
1 4 Alternative & Punk
2 6 Blues
3 11 Bossa Nova
4 24 Classical
5 22 Comedy
6 21 Drama
7 12 Easy Listening
8 15 Electronica/Dance
9 13 Heavy Metal
10 17 Hip Hop/Rap
11 2 Jazz
12 7 Latin
13 3 Metal
14 25 Opera
15 9 Pop
16 14 R&B/Soul
17 8 Reggae
18 1 Rock
19 5 Rock And Roll
20 20 Sci Fi & Fantasy
21 18 Science Fiction
22 10 Soundtrack
23 19 TV Shows
24 16 World

6) Retrieve all invoices from the year 2022, ordered by date.¶

In [38]:
query = """

SELECT *
FROM invoice
WHERE InvoiceDate >= '2022-01-01 00:00:00' 	
  AND InvoiceDate < '2023-01-01 00:00:00'
ORDER BY InvoiceDate ;

"""
df = pd.read_sql_query(query, engine)
df
Out[38]:
InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
0 84 43 2022-01-08 00:00:00 68, Rue Jouvence Dijon None France 21000 1.98
1 85 45 2022-01-08 00:00:00 Erzsébet krt. 58. Budapest None Hungary H-1073 1.98
2 86 47 2022-01-09 00:00:00 Via Degli Scipioni, 43 Rome RM Italy 00192 3.96
3 87 51 2022-01-10 00:00:00 Celsiusg. 9 Stockholm None Sweden 11230 6.94
4 88 57 2022-01-13 00:00:00 Calle Lira, 198 Santiago None Chile None 17.91
... ... ... ... ... ... ... ... ... ...
78 162 50 2022-12-15 00:00:00 C/ San Bernardo 85 Madrid None Spain 28015 1.98
79 163 52 2022-12-16 00:00:00 202 Hoxton Street London None United Kingdom N1 5LH 3.96
80 164 56 2022-12-17 00:00:00 307 Macacha Güemes Buenos Aires None Argentina 1106 5.94
81 165 3 2022-12-20 00:00:00 1498 rue Bélanger Montréal QC Canada H2G 1A7 8.91
82 166 12 2022-12-25 00:00:00 Praça Pio X, 119 Rio de Janeiro RJ Brazil 20040-020 13.86

83 rows × 9 columns

7) Calculate the average track duration for each genre.¶

In [39]:
query = """

SELECT ge.Name AS Genre,
       ROUND(AVG(tr.Milliseconds)/60000, 2) AS track_duration_minutes
FROM track AS tr
JOIN genre AS ge ON tr.GenreId = ge.GenreId
GROUP BY ge.GenreId
ORDER BY Genre ;

"""
df = pd.read_sql_query(query, engine)
df
Out[39]:
Genre track_duration_minutes
0 Alternative 4.40
1 Alternative & Punk 3.91
2 Blues 4.51
3 Bossa Nova 3.66
4 Classical 4.90
5 Comedy 26.42
6 Drama 42.92
7 Easy Listening 3.15
8 Electronica/Dance 5.05
9 Heavy Metal 4.96
10 Hip Hop/Rap 2.97
11 Jazz 4.86
12 Latin 3.88
13 Metal 5.16
14 Opera 2.91
15 Pop 3.82
16 R&B/Soul 3.67
17 Reggae 4.12
18 Rock 4.73
19 Rock And Roll 2.24
20 Sci Fi & Fantasy 48.53
21 Science Fiction 43.76
22 Soundtrack 4.07
23 TV Shows 35.75
24 World 3.75