"""Practice writing CRUD queries using SQLite and Python's DB-API. Author: Nicholas Tamassia Version: 2025-09-08 """ from pprint import pprint import sqlite3 def connect(path): """Connect to the SQLite database file and return a cursor. This function defines the global variables con and cur, which you will use throughout the module. THE CODE IS ALREADY FINISHED; DO NOT EDIT THIS FUNCTION. Args: path (str): File system path to the SQLite database file. Returns: sqlite3.Cursor: An object for executing SQL statements. """ global con, cur con = sqlite3.connect(path) cur = con.cursor() cur.execute("PRAGMA foreign_keys = ON") def create(): """Execute SQL statements that create two tables of your choice. Try to think of a unique example; no two students should have the same table/column names and design. Your tables must have at least five columns. At least one column must be an INTEGER, at least one column must be a REAL number, and at least one column must be TEXT. The first column of each table must be "id integer PRIMARY KEY". Generally, this is not a good design, but it makes autograding the assignment easier. The second table must have a FOREIGN KEY reference to the first table. Most but not all of the columns should be NOT NULL. """ cur.execute(""" CREATE TABLE IF NOT EXISTS Release ( id INTEGER PRIMARY KEY, title TEXT NOT NULL, format TEXT NOT NULL, sample_rate_khz REAL, release_year INTEGER NOT NULL ) """) cur.execute(""" CREATE TABLE IF NOT EXISTS Track ( id INTEGER PRIMARY KEY, title TEXT NOT NULL, duration_sec REAL NOT NULL, track_artist TEXT, release_id INTEGER, FOREIGN KEY (release_id) REFERENCES Release(id) ) """) def drop(): """Execute SQL statements that drop your tables, if they exist. This function is called at the beginning of the __main__ block so that you can run the program over and over again to test your code. """ cur.execute("DROP TABLE IF EXISTS Track") cur.execute("DROP TABLE IF EXISTS Release") def insert_sample(): """Execute SQL statements that insert three rows into each table. The rows you insert should have realistic data values that show an example of what the data might look like in each table. Please write one INSERT statement that inserts three rows, not three statements that insert one row each. At least one of the text values must have an apostrophe (Ex: "JMU's mascot is the Duke Dog"). Note: The id values (in the first column) should be automatically generated by SQLite. Do not include the id column in your code. """ cur.execute(""" INSERT INTO Release (title, format, sample_rate_khz, release_year) VALUES ('In Praise of Shadows', '2xCD', 44.1, 2016), ('Queen A''rcadia', 'CD', 44.1, 2015), ('Gravity Noize', 'Digital Media', 44.1, 2018); """) cur.execute(""" INSERT INTO Track (title, duration_sec, track_artist, release_id) VALUES ('Monochrome', 583.275, 'Proteus', 1), ('Bloody Duchess', 231.321, '葉月ゆら', 2), ('Storm Coming', 443.6743, 'Einhander', 1); """) def insert(title: str, format: float, sample_rate_khz: str, release_year: int): """Execute an SQL statement that inserts a row into the first table. The values must be passed as parameters to this function. If your table has 10 columns, then this function should have 9 parameters. As a matter of style, the parameter and column names must match. Note: The id value (in the first column) should be automatically generated by SQLite. Do not include the id column in your code. TODO Add parameters to the function definition and the docstring. Args: title (str): The title of the relase format (str): The format of the relase sample_rate_khs (float): The sample rate in kHz of the relase release_year (int): The year the release was released """ cur.execute(""" INSERT INTO Release (title, format, sample_rate_khz, release_year) VALUES (?, ?, ?, ?) """, (title, format, sample_rate_khz, release_year)) def select_all() -> list[tuple]: """Execute an SQL statement that selects all rows from the first table. Returns: list[tuple]: Each tuple represents a row of the table. """ return cur.execute(""" SELECT * FROM Release """).fetchall() def select(pk: int) -> tuple: """Execute an SQL statement that selects one row from the first table. Args: pk (int): The id of the row to select. Returns: tuple: The row for the specified pk, or None if not found. """ return cur.execute(""" SELECT * FROM Release WHERE Release.id = ? """, (pk,)).fetchone() def update(id: int, title: str, format: str, sample_rate_khz: float, release_year: int): """Execute an SQL statement that updates one row in the first table. The values must be passed as parameters to this function. If your table has 10 columns, then this function should have 10 parameters. As a matter of style, the parameter and column names must match. TODO Add parameters to the function definition and the docstring. Args: id (int): The id of the release to update title (str): The title of the relase format (str): The format of the relase sample_rate_khs (float): The sample rate in kHz of the relase release_year (int): The year the release was released """ cur.execute(""" UPDATE Release SET title = ?, format = ?, sample_rate_khz = ?, release_year = ? WHERE id = ? """, (title, format, sample_rate_khz, release_year, id)) def delete(pk): """Execute an SQL statement that deletes one row from the first table. Note that, because of the foreign key, you cannot delete a row that is referenced by the second table. If needed, modify the insert_sample() function to insert at least one row that is not related to the second table. Use that row's id to test this function. Args: pk (int): The id of the row to delete. """ cur.execute(""" DELETE FROM Release WHERE id = ? """, (pk,)) def insert_invalid(): """Cause the foreign key constraint to be violated by inserting a row. The purpose of this function is to demonstrate your understanding of foreign keys. Execute an SQL statement that inserts an invalid row into the second table. The values should be hard-coded -- don't use question marks in the query. SQLite should raise an IntegrityError when you call the cur.execute() method. """ cur.execute(""" INSERT INTO Track (title, duration_sec, track_artist, release_id) VALUES ('Personalizer', 473.2374, 'Electro.muster vo.みとせのりこ', 8); """) def update_invalid(): """Cause the foreign key constraint to be violated by updating a row. The purpose of this function is to demonstrate your understanding of foreign keys. Execute an SQL statement that updates a row in the second table. SQLite should raise an IntegrityError. The query values should be hard-coded -- don't use question marks. """ cur.execute(""" UPDATE Track SET release_id = 8 WHERE title = 'Storm Coming' """) def delete_invalid(): """Cause the foreign key constraint to be violated by deleting a row. The purpose of this function is to demonstrate your understanding of foreign keys. Execute an SQL statement that deletes a row in the first table. SQLite should raise an IntegrityError. The query values should be hard-coded -- don't use question marks. """ cur.execute(""" DELETE FROM Release WHERE title = 'In Praise of Shadows' """) if __name__ == "__main__": # Feel free to modify the path to your SQLite database file. # The autograder will use a different path for the database. connect("hw2.db") # The following code is provided to test your functions before submitting. # TODO Be sure to add the arguments required for insert() and update(). drop() create() insert_sample() pprint(select_all()) print() insert("The Personalizer", "CD", 44.1, 2012) pprint(select(2)) print() update(4, "The Personalizer [リクエスト盤]", "CD", 44.1, 2012) delete(4) pprint(select_all()) print() # The following tests make sure that your "invalid" functions work. try: insert_invalid() print("insert_invalid doesn't work") except sqlite3.IntegrityError: pass try: update_invalid() print("update_invalid doesn't work") except sqlite3.IntegrityError: pass try: delete_invalid() print("delete_invalid doesn't work") except sqlite3.IntegrityError: pass