Paper 2 Databases Answers
These answers correspond to Paper 2 Databases Drills.
Verification note: each model snippet was tested independently in a clean working directory.
The model answers below recreate and seed tables where needed so that each snippet can be tested independently.
Answer 1: Create Table
import sqlite3
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("""
CREATE TABLE Student (
student_id TEXT PRIMARY KEY,
name TEXT,
mark INTEGER
)
""")
conn.commit()
rows = conn.execute(
"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name"
).fetchall()
print(rows)
conn.close()Expected output:
[('Student',)]Mark points:
- imports
sqlite3; - connects to
school.db; - creates table
Student; - defines
student_idasTEXT PRIMARY KEY; - defines
nameandmarkfields with suitable types; - commits and shows table creation evidence.
Common weak answer:
- creating
student_idwithout a primary key constraint.
Answer 2: Insert Records
import sqlite3
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("CREATE TABLE Student (student_id TEXT PRIMARY KEY, name TEXT, mark INTEGER)")
records = [
("S01", "Asha", 74),
("S02", "Ben", 49),
("S03", "Chen", 82),
]
conn.executemany(
"INSERT INTO Student (student_id, name, mark) VALUES (?, ?, ?)",
records
)
conn.commit()
rows = conn.execute(
"SELECT student_id, name, mark FROM Student ORDER BY student_id"
).fetchall()
print(rows)
conn.close()Expected output:
[('S01', 'Asha', 74), ('S02', 'Ben', 49), ('S03', 'Chen', 82)]Mark points:
- creates or uses the correct table;
- stores records as tuples or equivalent;
- uses parameterised SQL with placeholders;
- inserts all three records;
- commits the changes;
- prints rows in the required order.
Common weak answer:
- building SQL by concatenating values into the statement string.
Answer 3: Read CSV to DB
import csv
import sqlite3
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("CREATE TABLE Student (student_id TEXT PRIMARY KEY, name TEXT, mark INTEGER)")
inserted = 0
with open("students.csv", "r", newline="") as file:
reader = csv.DictReader(file)
for row in reader:
conn.execute(
"INSERT INTO Student (student_id, name, mark) VALUES (?, ?, ?)",
(row["student_id"], row["name"], int(row["mark"]))
)
inserted = inserted + 1
conn.commit()
print(inserted)
conn.close()Expected output:
3Mark points:
- imports and uses
csv; - reads the header row correctly;
- creates or uses
Student; - converts
markto integer; - uses parameterised insert;
- inserts all CSV rows;
- commits the inserts;
- prints the correct inserted count.
Common weak answer:
- treating the header row as a student record.
Answer 4: Simple Query
import sqlite3
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("CREATE TABLE Student (student_id TEXT PRIMARY KEY, name TEXT, mark INTEGER)")
conn.executemany(
"INSERT INTO Student VALUES (?, ?, ?)",
[("S01", "Asha", 74), ("S02", "Ben", 49), ("S03", "Chen", 82)]
)
conn.commit()
rows = conn.execute(
"SELECT name FROM Student WHERE mark >= 50 ORDER BY name"
).fetchall()
for row in rows:
print(row[0])
conn.close()Expected output:
Asha
ChenMark points:
- uses
SELECT name; - uses table
Student; - filters with
mark >= 50; - orders by
name; - fetches and prints the matching names.
Common weak answer:
- using
mark > 50, which would wrongly exclude a mark of exactly50.
Answer 5: Join Query
import sqlite3
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("DROP TABLE IF EXISTS Class")
conn.execute("CREATE TABLE Class (class_code TEXT PRIMARY KEY, tutor TEXT)")
conn.execute("CREATE TABLE Student (student_id TEXT PRIMARY KEY, name TEXT, class_code TEXT)")
conn.executemany("INSERT INTO Class VALUES (?, ?)", [("24C1", "Ms Tan"), ("24C2", "Mr Lim")])
conn.executemany(
"INSERT INTO Student VALUES (?, ?, ?)",
[("S01", "Asha", "24C1"), ("S02", "Ben", "24C2"), ("S03", "Chen", "24C1")]
)
conn.commit()
rows = conn.execute("""
SELECT Student.name, Class.tutor
FROM Student
INNER JOIN Class
ON Student.class_code = Class.class_code
ORDER BY Student.name
""").fetchall()
for name, tutor in rows:
print(name + " - " + tutor)
conn.close()Expected output:
Asha - Ms Tan
Ben - Mr Lim
Chen - Ms TanMark points:
- creates or uses both tables;
- inserts the given class and student data;
- joins
StudenttoClass; - uses matching
class_codefields; - selects student name and tutor;
- orders or prints results clearly;
- produces the required output.
Common weak answer:
- joining without an
ONcondition.
Answer 6: Update Record
import sqlite3
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("CREATE TABLE Student (student_id TEXT PRIMARY KEY, name TEXT, mark INTEGER)")
conn.executemany(
"INSERT INTO Student VALUES (?, ?, ?)",
[("S01", "Asha", 74), ("S02", "Ben", 49), ("S03", "Chen", 82)]
)
conn.execute("UPDATE Student SET mark = ? WHERE student_id = ?", (55, "S02"))
conn.commit()
row = conn.execute(
"SELECT student_id, name, mark FROM Student WHERE student_id = ?",
("S02",)
).fetchone()
print(row)
conn.close()Expected output:
('S02', 'Ben', 55)Mark points:
- uses
UPDATE; - sets
markto55; - uses
WHERE student_id = ?; - uses parameterised values;
- commits the update;
- prints the updated row.
Common weak answer:
- omitting the
WHEREclause, which updates every student’s mark.
Answer 7: Delete Record
import sqlite3
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("CREATE TABLE Student (student_id TEXT PRIMARY KEY, name TEXT, mark INTEGER)")
conn.executemany(
"INSERT INTO Student VALUES (?, ?, ?)",
[("S01", "Asha", 74), ("S02", "Ben", 49), ("S03", "Chen", 82)]
)
conn.execute("DELETE FROM Student WHERE student_id = ?", ("S02",))
conn.commit()
rows = conn.execute("SELECT student_id FROM Student ORDER BY student_id").fetchall()
print(rows)
conn.close()Expected output:
[('S01',), ('S03',)]Mark points:
- uses
DELETE FROM Student; - uses a
WHEREclause; - uses parameterised key value;
- commits the deletion;
- prints only the remaining IDs.
Common weak answer:
- omitting the
WHEREclause and deleting all records.
Answer 8: NoSQL JSON
import json
def events_with_tag(filename, tag):
with open(filename, "r", encoding="utf-8") as file:
events = json.load(file)
titles = []
for event in events:
if tag in event["tags"]:
titles.append(event["title"])
return titles
print(events_with_tag("events.json", "database"))Expected output:
['Web Apps', 'Data Night']Mark points:
- imports and uses
json; - loads the file into Python structures;
- treats the outer data as a list of dictionaries;
- accesses the nested
tagslist; - filters events containing the requested tag;
- returns matching titles;
- shows the required output.
Common weak answer:
- checking
event["tag"]when the field is namedtagsand stores a list.
Answer 9: Integrity Check
import sqlite3
def safe_insert_student(conn, student_id, name, mark):
existing = conn.execute(
"SELECT student_id FROM Student WHERE student_id = ?",
(student_id,)
).fetchone()
if existing is not None:
return False
conn.execute(
"INSERT INTO Student (student_id, name, mark) VALUES (?, ?, ?)",
(student_id, name, mark)
)
conn.commit()
return True
conn = sqlite3.connect("school.db")
conn.execute("DROP TABLE IF EXISTS Student")
conn.execute("CREATE TABLE Student (student_id TEXT PRIMARY KEY, name TEXT, mark INTEGER)")
print(safe_insert_student(conn, "S01", "Asha", 74))
print(safe_insert_student(conn, "S01", "Anya", 88))
row_count = conn.execute("SELECT COUNT(*) FROM Student").fetchone()[0]
print(row_count)
conn.close()Expected output:
True
False
1Mark points:
- queries for an existing ID first;
- uses parameterised SQL;
- returns
Falsefor duplicate ID; - inserts only when ID is absent;
- commits successful insert;
- returns
Truefor successful insert; - prints final row count showing no duplicate was inserted.
Common weak answer:
- checking duplicate names instead of duplicate primary keys.
Answer 10: DB Path Debug
import os
import sqlite3
db_name = "school.db"
conn = sqlite3.connect(db_name)
path = os.path.abspath(db_name)
print(path)
print(path.endswith("school.db"))
conn.close()Expected output:
/.../school.db
TrueThe exact absolute path depends on the working directory.
Mark points:
- connects to
school.db; - obtains an absolute path;
- prints the absolute path and whether it ends with
school.db; - closes the connection.
Common weak answer:
- printing only
"school.db", which does not reveal the working directory being used.