My journey with Python and SQLite | Part 3

I added the remaining CRUD statements in Part 2. In this post, I’ll DRY up the code used for executing and committing the SQL statements.

Create a new function that accepts the database path and the SQL statement. Create a single unit of work by pulling in the connection and cursor creation and closure, statement execution, and results. As this evolves into an app or a library, I would rather open the connection, do some work, and close the connection rather than worry about leaving a connection open by accident.

def query_db(db_path, sql):
    # Open and connection and create a cursor
    conn = sqlite3.connect(db_path)
    cur = conn.cursor()

    # Execute the query and fetch the results
    cur = conn.execute(sql)
    conn.commit()  # If there are no open transactions, it is a no-op
    res = cur.fetchall()  # If there are no records, returns an empty list []

    # Close the cursor and connection
    cur.close()
    conn.close()

    return res

Not all of the SQL statements executed from Python need the conn.commit() code. Per the documentation[1], the commit() method is a “no-op” and does nothing when there are no open transactions. Additionally, the documentation[2][3] indicates that fectchone() returns None[2] and fetchall() returns an empty list [][3] if there are no records to fetch. Use fetchall() to cover all bases for now. In the future, I may add some conditional statements to change what is returned from the function. For now, it is clean, and that is good for me.

Now execute the single function after each SQL statement and print the result if desired.

    # Read a record by id
    sql = "SELECT ROWID, name, comments FROM institutions WHERE ROWID = 1"
    res = query_db(db_path, sql)
    print(res)

Here is the module.

institution_03.py

import sqlite3
import sys
from pathlib import Path


def query_db(db_path, sql):
    # Open and connection and create a cursor
    conn = sqlite3.connect(db_path)
    cur = conn.cursor()

    # Execute the query and fetch the results
    cur = conn.execute(sql)
    conn.commit()  # If there are no open transactions, it is a no-op
    res = cur.fetchall()  # If there are no records, returns an empty list []

    # Close the cursor and connection
    cur.close()
    conn.close()

    return res


def main():
    db_path = Path(".") / "home.db"

    # Create the table
    sql = "CREATE TABLE IF NOT EXISTS institutions (name, comments)"
    res = query_db(db_path, sql)

    # Create one record
    sql = """INSERT INTO institutions (name, comments)
            VALUES ('ABC Bank', 'A regional bank')"""
    res = query_db(db_path, sql)

    # Create many records
    sql = """INSERT INTO institutions (name, comments)
            VALUES ('Chase', 'International'), ('Discover', 'National')"""
    res = query_db(db_path, sql)

    # Read a record by id
    sql = "SELECT ROWID, name, comments FROM institutions WHERE ROWID = 1"
    res = query_db(db_path, sql)
    print(res)

    # Read all records
    sql = "SELECT ROWID, name, comments FROM institutions"
    res = query_db(db_path, sql)
    print(res)

    # Update a record by id
    sql = "UPDATE institutions SET name = 'My Bank' WHERE ROWID = 1"
    res = query_db(db_path, sql)

    # Update all records
    sql = "UPDATE institutions SET comments = 'Comments are stupid'"
    res = query_db(db_path, sql)

    # Delete one record from the table by id
    sql = "DELETE FROM institutions WHERE ROWID = 1"
    res = query_db(db_path, sql)

    # Delete all records from the table
    sql = "DELETE FROM institutions"
    res = query_db(db_path, sql)

    # Delete the table
    sql = "DROP TABLE IF EXISTS institutions"
    res = query_db(db_path, sql)


if __name__ == "__main__":
    sys.exit(main())

My journey with Python and SQLite

References:

  1. sqlite3 — DB-API 2.0 interface for SQLite databases, Python.org Documentation
  2. sqlite3 — DB-API 2.0 interface for SQLite databases | Cursor.fetchone, Python.org Documentation
  3. sqlite3 — DB-API 2.0 interface for SQLite databases | Cursor.fetchall, Python.org Documentation
Brian Johnson @brian3johnson