Lecture 05 -- DDL, DML & Constraints¶
# Run this cell to set up imports
import numpy as np
import pandas as pd
%reload_ext sql
!createdb lecture5 -h localhost
createdb: error: database creation failed: ERROR: database "lecture5" already exists
%sql postgresql://127.0.0.1:5432/lecture5
Manager demo¶
Creating the manager relation
%%sql
DROP TABLE IF EXISTS managers;
CREATE TABLE managers (
manager_name VARCHAR(20),
age INTEGER,
address TEXT,
manager_id INTEGER
);
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|
Add a tuple
%%sql
INSERT INTO managers
(manager_id, age, manager_name)
VALUES
(1, 23, 'Aditya'),
(2, 23, 'Lisa')
;
/***********/
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
Aditya | 23 | None | 1 |
Lisa | 23 | None | 2 |
What if we add a new tuple?
%%sql
INSERT INTO managers
(manager_id, manager_name, age)
VALUES
(1, 'Michael', 123);
/***********/
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
Aditya | 23 | None | 1 |
Lisa | 23 | None | 2 |
Michael | 123 | None | 1 |
Whoops! We can have two tuples with the same ID!
Alternate Managers Schema
One way to to fix is to let the system set the ID.
This replaces the manager_id
type with a SERIAL
instead of an INTEGER
.
%%sql
DROP TABLE IF EXISTS managers;
CREATE TABLE managers(
manager_name VARCHAR(20),
age INTEGER,
address TEXT,
manager_id SERIAL
);
/***********/
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|
%%sql
INSERT INTO managers
(age, manager_name)
VALUES
(23, 'Aditya'),
(23, 'Lisa')
;
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
Aditya | 23 | None | 1 |
Lisa | 23 | None | 2 |
And we can add another tuple...
%%sql
INSERT INTO managers
(manager_name, age)
VALUES
('Michael', 123);
/***********/
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
Aditya | 23 | None | 1 |
Lisa | 23 | None | 2 |
Michael | 123 | None | 3 |
Adding in Constraints¶
%%sql
DROP TABLE IF EXISTS managers;
CREATE TABLE managers (
manager_name VARCHAR(20) UNIQUE,
age INTEGER DEFAULT 50,
address TEXT,
manager_id SERIAL PRIMARY KEY
);
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|
%%sql
INSERT INTO managers
(age, manager_name)
VALUES
(23, 'Aditya'),
(23, 'Lisa')
;
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
Aditya | 23 | None | 1 |
Lisa | 23 | None | 2 |
%%sql
INSERT INTO managers
(manager_name)
VALUES
('Michael');
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
Aditya | 23 | None | 1 |
Lisa | 23 | None | 2 |
Michael | 50 | None | 3 |
Can't insert another Michael due to the UNIQUE constraint!
%%sql
INSERT INTO managers
(manager_name)
VALUES
('Michael');
SELECT * FROM managers;
RuntimeError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "managers_manager_name_key" DETAIL: Key (manager_name)=(Michael) already exists. [SQL: INSERT INTO managers (manager_name) VALUES ('Michael');] (Background on this error at: https://sqlalche.me/e/20/gkpj) If you need help solving this issue, send us a message: https://ploomber.io/community
OK what if we update Michael's ID?
%%sql
UPDATE managers
SET manager_id = manager_id + 1
WHERE manager_name = 'Michael';
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
Aditya | 23 | None | 1 |
Lisa | 23 | None | 2 |
Michael | 50 | None | 4 |
This works, but will this work?
%%sql
UPDATE managers
SET manager_id = manager_id - 1
WHERE manager_name = 'Lisa';
SELECT * FROM managers;
RuntimeError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "managers_pkey" DETAIL: Key (manager_id)=(1) already exists. [SQL: UPDATE managers SET manager_id = manager_id - 1 WHERE manager_name = 'Lisa';] (Background on this error at: https://sqlalche.me/e/20/gkpj) If you need help solving this issue, send us a message: https://ploomber.io/community
ALTER TABLES¶
%%sql
ALTER TABLE managers
DROP address,
DROP age,
ADD income REAL DEFAULT 1000000.0;
/***********/
SELECT * FROM managers;
manager_name | manager_id | income |
---|---|---|
Aditya | 1 | 1000000.0 |
Lisa | 2 | 1000000.0 |
Michael | 4 | 1000000.0 |
Beware of UNIQUE
and NULL
values!!
%%sql
DROP TABLE IF EXISTS managers;
CREATE TABLE managers (
manager_name VARCHAR(20) UNIQUE,
age INTEGER DEFAULT 50,
address TEXT,
manager_id SERIAL PRIMARY KEY
);
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|
%%sql
INSERT INTO managers(age)
VALUES
(100),
(NULL);
%%sql
SELECT * FROM managers;
manager_name | age | address | manager_id |
---|---|---|---|
None | 100 | None | 1 |
None | None | None | 2 |
Notice Even though we can't have duplicate names, NULL isn't considered a duplicate.
Delete the relation entirely
%%sql
DROP TABLE managers;
IMDB Database¶
%reload_ext sql
%sql postgresql://127.0.0.1:5432/lecture5
%%sql
DROP TABLE IF EXISTS actors CASCADE;
DROP TABLE IF EXISTS movies CASCADE;
DROP TABLE IF EXISTS cast_info;
CREATE TABLE actors (
id INTEGER,
name TEXT,
PRIMARY KEY(id)
);
CREATE TABLE movies (
id INTEGER,
title TEXT,
PRIMARY KEY(id)
);
CREATE TABLE cast_info (
person_id INTEGER,
movie_id INTEGER,
FOREIGN KEY (person_id)
REFERENCES actors (id)
ON DELETE SET NULL
ON UPDATE CASCADE,
FOREIGN KEY (movie_id)
REFERENCES movies (id)
ON DELETE SET NULL);
INSERT INTO actors VALUES
(1, 'Tom Hanks'),
(3, 'Michelle Yeoh')
;
INSERT INTO movies VALUES
(23, 'Forrest Gump'),
(45, 'Tomorrow Never Dies')
;
INSERT INTO cast_info VALUES
(1, 23),
(3, 45)
;
%%sql
SELECT * FROM cast_info;
person_id | movie_id |
---|---|
1 | 23 |
3 | 45 |
A. What if we… Delete a tuple from Actor corresponding to id = 1?
%%sql
DELETE FROM actors
WHERE id = 1;
SELECT * FROM cast_info;
(note: reset table layout for each choice)
B. Change a tuple in Actor from id = 1 to id = 2?
%%sql
UPDATE actors
SET id = 2
WHERE id = 1;
SELECT * FROM actors;
%%sql
SELECT * FROM cast_info;
C. Delete a tuple from Movie corresponding to id = 23?
%%sql
DELETE FROM movies
WHERE id = 23;
SELECT * FROM cast_info;
D. Change a tuple in Movie from id = 23 to id = 24?
%%sql
UPDATE movies
SET id = 24
WHERE id = 23;
E. Insert a tuple into cast_info
that adds a new person_id not found in Actor?
%%sql
INSERT INTO cast_info VALUES
(467, 23)
;