ZetCode

Python sqlite3.Connection.execute Method

Last modified April 15, 2025

This comprehensive guide explores Python's sqlite3.Connection.execute method, the primary way to execute SQL statements with SQLite databases.

Basic Definitions

The execute method executes a single SQL statement on a database connection. It's available directly on connection objects for convenience.

Key characteristics: it returns a cursor object, accepts parameterized queries, and handles both DDL and DML statements. It combines cursor creation and execution in one step.

Basic SQL Execution

Here's the simplest usage of execute to create a table and insert data.

basic_execute.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    # Create table using execute
    conn.execute('''CREATE TABLE IF NOT EXISTS users
                    (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)''')
    
    # Insert data with parameters
    conn.execute("INSERT INTO users (name, age) VALUES (?, ?)", ('Alice', 30))
    
    # Commit is automatic with 'with' statement

This example shows basic CRUD operations using execute. The 'with' statement ensures proper resource cleanup.

Parameterized queries (using ? placeholders) are recommended to prevent SQL injection and improve performance with repeated queries.

Querying Data

The execute method can run SELECT queries and return cursor objects for result processing.

query_data.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    # Execute query and get cursor
    cursor = conn.execute("SELECT * FROM users WHERE age > ?", (25,))
    
    # Process results
    for row in cursor:
        print(f"ID: {row[0]}, Name: {row[1]}, Age: {row[2]}")

The example demonstrates querying data with a parameter. The cursor returned by execute is iterable.

Row data is accessed by index by default. We'll show named access in later examples.

Multiple Parameter Execution

The executemany method (related to execute) processes multiple parameter sets efficiently.

executemany.py
import sqlite3

users = [
    ('Bob', 25),
    ('Charlie', 40),
    ('Diana', 35)
]

with sqlite3.connect('example.db') as conn:
    conn.executemany("INSERT INTO users (name, age) VALUES (?, ?)", users)

This is more efficient than individual execute calls for bulk inserts. The transaction is handled automatically.

Each tuple in the users list corresponds to one set of parameters for the query.

Named Parameters

SQLite supports named parameters (using :name syntax) for more readable queries.

named_params.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    # Using named parameters
    conn.execute("""
        UPDATE users 
        SET age = :new_age 
        WHERE name = :user_name
    """, {'new_age': 32, 'user_name': 'Alice'})
    
    # Verify update
    cursor = conn.execute("SELECT age FROM users WHERE name = ?", ('Alice',))
    print("New age:", cursor.fetchone()[0])

Named parameters make queries more readable and maintainable, especially with many parameters.

The parameter dictionary keys must match the named placeholders in the SQL.

Row Factories

Row factories enable named column access instead of just positional access.

row_factory.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    # Set row factory for named access
    conn.row_factory = sqlite3.Row
    
    cursor = conn.execute("SELECT * FROM users LIMIT 1")
    row = cursor.fetchone()
    
    # Access columns by name
    print(f"User {row['name']} is {row['age']} years old")

The sqlite3.Row factory provides both index and name-based access to columns.

This makes code more robust against schema changes (column order) and more readable.

Transactions

The execute method participates in SQLite's automatic transactions.

transactions.py
import sqlite3

with sqlite3.connect('transactions.db') as conn:
    try:
        conn.execute("CREATE TABLE IF NOT EXISTS accounts (id INTEGER, balance REAL)")
        conn.execute("INSERT INTO accounts VALUES (1, 1000.0)")
        conn.execute("INSERT INTO accounts VALUES (2, 500.0)")
        
        # Transfer money
        conn.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
        conn.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
        
        # Will commit automatically if no exceptions
    except sqlite3.Error as e:
        print("Transaction failed:", e)
        # Automatic rollback occurs on exception

SQLite automatically starts a transaction before DML statements. The 'with' statement commits on success or rolls back on exception.

For explicit control, use BEGIN, COMMIT, and ROLLBACK statements.

Custom Functions

SQLite can call Python functions from SQL via execute.

custom_functions.py
import sqlite3

def calculate_bonus(age):
    return age * 10  # Simple bonus calculation

with sqlite3.connect(':memory:') as conn:
    conn.create_function("bonus", 1, calculate_bonus)
    
    conn.execute("CREATE TABLE employees (name TEXT, age INTEGER)")
    conn.execute("INSERT INTO employees VALUES ('Alice', 30)")
    
    # Use Python function in SQL
    cursor = conn.execute("""
        SELECT name, age, bonus(age) as bonus 
        FROM employees
    """)
    
    for row in cursor:
        print(f"{row['name']}: {row['age']} years, ${row['bonus']} bonus")

This registers a Python function as a SQL function. The function can then be called from SQL statements.

Custom functions extend SQLite's capabilities with Python logic while maintaining query performance.

Best Practices

Source References

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.