Intro to Databases & ORMs
CSCI 338: Software Engineering
Spring 2025
Announcements
Outline
Outline
What is a database?
A database is an organized collection of structured information, or data, typically stored electronically in a computer system.
How is this better than just storing data as a text file or in memory (e.g., https://meteor.unca.edu/registrar/class-schedules/api/v1/courses/2025/fall/) ?�
Why would you want to use a database?
Why would you want to use a database?
Types of Databases
There are many different kinds of databases, but the two most common “families” of databases are:
Types of Databases: Relational (SQL) Databases
Types of Databases: NoSQL Databases
Outline
Activity: Set Up Your Database!
What did we just set up?
����� Port 5433������Your Laptop communicates with port 5432�via DBeaver + Python client
PostgreSQL Database on Docker Container running on port 5432
Outline
What is SQL?
SQL is a declarative programming language
Meaning, you tell SQL what data operations you want it to execute, but the underlying database system figures out how to actually go about manipulating / retrieving the data.
In declarative languages, you specify the what, not the how
What other languages have you seen (recently) that are also declarative?
SQL is not only used to manipulate data, but also to define the structure and relationships of your data.
PostgreSQL Reference Documentation
Let’s navigate to Docker…
Let’s hop onto your Docker-hosted bash terminal. Do you remember the commands?
ps -a # to get your process id
docker exec -it <pid> bash # to get on Docker command line
Now let’s access PostgreSQL
From the Docker terminal, jump onto the postgresql command line interface:
psql -U postgres # activate the psql CLI�
> \l # list all of the databases
> \du # list all of the database users
> \c dvdrentals # connect to the DVD database
psql administrative commands
\q | Exits the psql shell |
|
\l | Lists all the available databases |
|
\c <dbname> <username> | Connect to specific database | \c photo_app_tutorial postgres |
\dt | Lists all of the tables in the database you’re connected to |
|
\d <table_name> | Describes the structure (i.e., “schema”) of a table | \d posts |
\du | List all users and their roles |
|
space bar | If you query data in a table that has multiple pages, the space bar will show you the next set of records. |
|
q | If you query data in a table that has multiple pages, and you want to go back to the psql prompt. |
|
Let’s look at your database…
First some basics:
Quick Crash Course on Querying
Let’s practice some queries (to be continued in lab)...
film_id | title
---------+---------------------
1 | Academy Dinosaur
2 | Ace Goldfinger
3 | Adaptation Holes
4 | Affair Prejudice
5 | African Egg
6 | Agent Truman
7 | Airplane Sierra
8 | Airport Pollock
9 | Alabama Devil
10 | Aladdin Calendar
11 | Alamo Videotape
12 | Alaska Phantom
13 | Ali Forever
14 | Alice Fantasia
15 | Alien Center
16 | Alley Evolution
17 | Alone Trip
18 | Alter Victory
19 | Amadeus Holy
20 | Amelie Hellfighters
film_id | category_id
---------+-------------
1 | 6
2 | 11
3 | 6
4 | 11
5 | 8
6 | 9
7 | 5
8 | 11
9 | 11
10 | 15
11 | 9
12 | 12
13 | 11
14 | 4
15 | 9
16 | 9
17 | 12
18 | 2
19 | 1
19 | 12
category_id | name
-------------+-------------
1 | Action
2 | Animation
3 | Children
4 | Classics
5 | Comedy
6 | Documentary
7 | Drama
8 | Family
9 | Foreign
10 | Games
11 | Horror
12 | Music
13 | New
14 | Sci-Fi
15 | Sports
16 | Travel
film table
film_category table
category table
There are a few different ways to join tables together….
title | name
---------------------+-------------
Academy Dinosaur | Documentary
Ace Goldfinger | Horror
Adaptation Holes | Documentary
Affair Prejudice | Horror
African Egg | Family
Agent Truman | Foreign
Airplane Sierra | Comedy
Airport Pollock | Horror
Alabama Devil | Horror
Aladdin Calendar | Sports
Alamo Videotape | Foreign
Alaska Phantom | Music
Ali Forever | Horror
Alice Fantasia | Classics
Alien Center | Foreign
Alley Evolution | Foreign
Alone Trip | Music
Alter Victory | Animation
Amadeus Holy | Action
Amelie Hellfighters | Music
SELECT film.title, category.name
FROM film
JOIN film_category
ON film.film_id = film_category.film_id
JOIN category
ON film_category.category_id = category.category_id
ORDER BY film.film_id
LIMIT 20;��
Green = First join connects film to film_category (joins on film_id column)
Yellow = Second join connects film_category to category (joins on category_id column)
Solution
Option 1. JOIN Syntax
title | name
---------------------+-------------
Academy Dinosaur | Documentary
Ace Goldfinger | Horror
Adaptation Holes | Documentary
Affair Prejudice | Horror
African Egg | Family
Agent Truman | Foreign
Airplane Sierra | Comedy
Airport Pollock | Horror
Alabama Devil | Horror
Aladdin Calendar | Sports
Alamo Videotape | Foreign
Alaska Phantom | Music
Ali Forever | Horror
Alice Fantasia | Classics
Alien Center | Foreign
Alley Evolution | Foreign
Alone Trip | Music
Alter Victory | Animation
Amadeus Holy | Action
Amelie Hellfighters | Music
SELECT film.title, category.name
FROM film, film_category, category
WHERE
film.film_id = film_category.film_id AND
film_category.category_id = category.category_id
ORDER BY film.film_id
LIMIT 20;��
Green = Which tables to pull from
Yellow = Connects columns together the tables.
Solution
Option 2. WHERE syntax
title | name
---------------------+-------------
Academy Dinosaur | Documentary
Ace Goldfinger | Horror
Adaptation Holes | Documentary
Affair Prejudice | Horror
African Egg | Family
Agent Truman | Foreign
Airplane Sierra | Comedy
Airport Pollock | Horror
Alabama Devil | Horror
Aladdin Calendar | Sports
Alamo Videotape | Foreign
Alaska Phantom | Music
Ali Forever | Horror
Alice Fantasia | Classics
Alien Center | Foreign
Alley Evolution | Foreign
Alone Trip | Music
Alter Victory | Animation
Amadeus Holy | Action
Amelie Hellfighters | Music
WITH film_table AS (
SELECT f.film_id, f.title, fc.category_id
FROM film AS f � JOIN film_category AS fc
ON f.film_id = fc.film_id
)
SELECT f.film_id, f.title, c.name
FROM film_table AS f�JOIN category AS c
ON f.category_id = c.category_id
ORDER BY f.film_id;
Defines a temporary result set that can be referenced within another SQL statement
Solution
Option 3. Common Table Expression (CTE) syntax – Thanks Connor :)
SQL: INSERT
INSERT INTO table_name(column1, column2, …)
VALUES (value1, value2, …);
SQL: UPDATE
UPDATE table_name
SET column1 = value1,
column2 = value2,
column3 = value3,
...
WHERE condition;
SQL: DELETE
DELETE FROM table_name
WHERE condition;
Intro to Object Relational Mapping
What is SQLAlchemy?
SQLAlchemy is a python abstraction that makes communication with databases “easier.”
Some Terminology
What is a Model?
This approach – known as “Object Relational Mapping” – allows a more convenient way to manipulate data via the Python language.
What is a database session?
A database session handles the following
async with AsyncSession(engine) as session:
ORM Activity
Walkthrough of the orm_samples.py file.
How do we do the same kind of join using SQLAlchemy?!
film_id | title
---------+---------------------
1 | Academy Dinosaur
2 | Ace Goldfinger
3 | Adaptation Holes
4 | Affair Prejudice
5 | African Egg
6 | Agent Truman
7 | Airplane Sierra
8 | Airport Pollock
9 | Alabama Devil
10 | Aladdin Calendar
11 | Alamo Videotape
12 | Alaska Phantom
13 | Ali Forever
14 | Alice Fantasia
15 | Alien Center
16 | Alley Evolution
17 | Alone Trip
18 | Alter Victory
19 | Amadeus Holy
20 | Amelie Hellfighters
film_id | category_id
---------+-------------
1 | 6
2 | 11
3 | 6
4 | 11
5 | 8
6 | 9
7 | 5
8 | 11
9 | 11
10 | 15
11 | 9
12 | 12
13 | 11
14 | 4
15 | 9
16 | 9
17 | 12
18 | 2
19 | 1
20 | 12
category_id | name
-------------+-------------
1 | Action
2 | Animation
3 | Children
4 | Classics
5 | Comedy
6 | Documentary
7 | Drama
8 | Family
9 | Foreign
10 | Games
11 | Horror
12 | Music
13 | New
14 | Sci-Fi
15 | Sports
16 | Travel
film table
film_category table
category table
We create models that define relationships…
class Film(Base):
__tablename__ = 'film'
film_id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
….
language = relationship('Language', back_populates='films')
actors = relationship('Actor', secondary='film_actor', back_populates='films')
categories = relationship('Category', secondary='film_category', back_populates='films')
inventories = relationship('Inventory', back_populates='film')
We create models that define relationships…
class FilmCategory(Base):
__tablename__ = 'film_category'
film_id = Column(Integer, ForeignKey('film.film_id'), primary_key=True)
category_id = Column(Integer, ForeignKey('category.category_id'), primary_key=True)
last_update = Column(TIMESTAMP, nullable=False, default=datetime.utcnow)
We create models that define relationships…
class Category(Base):
__tablename__ = 'category'
category_id = Column(Integer, primary_key=True)
name = Column(String(25), nullable=False)
last_update = Column(TIMESTAMP, nullable=False, default=datetime.utcnow)
films = relationship('Film', secondary='film_category', back_populates='categories')
…making the query easier
result = await session.execute(
select(Film.title, Category.name)
.join(Film.categories)
.order_by(Film.title)
)