Unit 2.4b Using Programs with Data, SQL
Using Programs with Data is focused on SQL and database actions. Part B focuses on learning SQL commands, connections, and curses using an Imperative programming style,
Database Programming is Program with Data
Each Tri 2 Final Project should be an example of a Program with Data.
Prepare to use SQLite in common Imperative Technique
- Explore SQLite Connect object to establish database connection- Explore SQLite Cursor Object to fetch data from a table within a database
 
Schema of Users table in Sqlite.db
Uses PRAGMA statement to read schema.
Describe Schema, here is resource Resource- What is a database schema? the layout of a database written in code
- What is the purpose of identity Column in SQL database? An identity makes it easier to differentiate between users that share certain values.
 - What is the purpose of a primary key in SQL database? This column is used as a sort of master key to select user.
 - What are the Data Types in SQL table? The most common data type in sql databases is string.
 
import sqlite3
database = 'instance/sqlite.db' # this is location of database
def schema():
    
    # Connect to the database file
    conn = sqlite3.connect(database)
    # Create a cursor object to execute SQL queries
    cursor = conn.cursor()
    
    # Fetch results of Schema
    results = cursor.execute("PRAGMA table_info('users')").fetchall()
    # Print the results
    for row in results:
        print(row)
    # Close the database connection
    conn.close()
    
schema()
Reading Users table in Sqlite.db
Uses SQL SELECT statement to read data
- What is a connection object? After you google it, what do you think it does? It is used to create cursor objects that can manipulate data
 - Same for cursor object? An object that can be used to target certain data in a database.
 - Look at conn object and cursor object in VSCode debugger. What attributes are in the object?
 - Is "results" an object? How do you know?
 
import sqlite3
def read():
    # Connect to the database file
    conn = sqlite3.connect(database)
    # Create a cursor object to execute SQL queries
    cursor = conn.cursor()
    
    # Execute a SELECT statement to retrieve data from a table
    results = cursor.execute('SELECT * FROM users').fetchall()
    # Print the results
    if len(results) == 0:
        print("Table is empty")
    else:
        for row in results:
            print(row)
    # Close the cursor and connection objects
    cursor.close()
    conn.close()
    
read()
import sqlite3
def create():
    name = input("Enter your name:")
    uid = input("Enter your user id:")
    password = input("Enter your password")
    dob = input("Enter your date of birth 'YYYY-MM-DD'")
    
    # Connect to the database file
    conn = sqlite3.connect(database)
    # Create a cursor object to execute SQL commands
    cursor = conn.cursor()
    try:
        # Execute an SQL command to insert data into a table
        cursor.execute("INSERT INTO users (_name, _uid, _password, _dob) VALUES (?, ?, ?, ?)", (name, uid, password, dob))
        
        # Commit the changes to the database
        conn.commit()
        print(f"A new user record {uid} has been created")
                
    except sqlite3.Error as error:
        print("Error while executing the INSERT:", error)
    # Close the cursor and connection objects
    cursor.close()
    conn.close()
    
create()
import sqlite3
def update():
    uid = input("Enter user id to update")
    password = input("Enter updated password")
    if len(password) < 2:
        message = "hacked"
        password = 'gothackednewpassword123'
    else:
        message = "successfully updated"
    # Connect to the database file
    conn = sqlite3.connect(database)
    # Create a cursor object to execute SQL commands
    cursor = conn.cursor()
    try:
        # Execute an SQL command to update data in a table
        cursor.execute("UPDATE users SET _password = ? WHERE _uid = ?", (password, uid))
        if cursor.rowcount == 0:
            # The uid was not found in the table
            print(f"No uid {uid} was not found in the table")
        else:
            print(f"The row with user id {uid} the password has been {message}")
            conn.commit()
    except sqlite3.Error as error:
        print("Error while executing the UPDATE:", error)
        
    
    # Close the cursor and connection objects
    cursor.close()
    conn.close()
    
#update()
Delete a User in table in Sqlite.db
Uses a delete function to remove a user based on a user input of the id.
- Is DELETE a dangerous operation? Why? If delete is programmed incorrectly it can delete data without confirmation.
 - In the print statemements, what is the "f" and what does {uid} do? the F makes it so that items in {} are formatted with the value in the brackets
 
import sqlite3
def delete():
    uid = input("Enter user id to delete")
    # Connect to the database file
    conn = sqlite3.connect(database)
    # Create a cursor object to execute SQL commands
    cursor = conn.cursor()
    
    try:
        cursor.execute("DELETE FROM users WHERE _uid = ?", (uid,))
        if cursor.rowcount == 0:
            # The uid was not found in the table
            print(f"No uid {uid} was not found in the table")
        else:
            # The uid was found in the table and the row was deleted
            print(f"The row with uid {uid} was successfully deleted")
        conn.commit()
    except sqlite3.Error as error:
        print("Error while executing the DELETE:", error)
        
    # Close the cursor and connection objects
    cursor.close()
    conn.close()
    
#delete()
def menu():
    operation = input("Enter: (C)reate (R)ead (U)pdate or (D)elete or (S)chema")
    if operation.lower() == 'c':
        create()
    elif operation.lower() == 'r':
        read()
    elif operation.lower() == 'u':
        update()
    elif operation.lower() == 'd':
        delete()
    elif operation.lower() == 's':
        schema()
    elif len(operation)==0: # Escape Key
        return
    else:
        print("Please enter c, r, u, or d") 
    menu() # recursion, repeat menu
        
try:
    menu() # start menu
except:
    print("Perform Jupyter 'Run All' prior to starting menu")
def menu():
    operation = input("Enter: (C)reate (R)ead (U)pdate or (D)elete or (S)chema")
    if operation.lower() == 'c':
        create()
    elif operation.lower() == 'r':
        read()
    elif operation.lower() == 'u':
        update()
    elif operation.lower() == 'd':
        delete()
    elif operation.lower() == 's':
        schema()
    elif len(operation)==0: # Escape Key
        return
    else:
        print("Please enter c, r, u, or d") 
    menu() # recursion, repeat menu
        
try:
    menu() # start menu
except:
    print("Perform Jupyter 'Run All' prior to starting menu")
Hacks
- Add this Blog to you own Blogging site. In the Blog add notes and observations on each code cell.
 - In this implementation, do you see procedural abstraction?
 - In 2.4a or 2.4b lecture
- Do you see data abstraction? Complement this with Debugging example.
 - Use Imperative or OOP style to Create a new Table or do something that applies to your CPT project.
 
 
Reference... sqlite documentation
I see procedural abstraction in the Create Update Read and Delete functions.
Data abstraction is the whole purpose of using a database. Data is placed into lists/dictionaries and then into the database.