Python tutorials > Working with External Resources > Databases > How to execute SQL queries?

How to execute SQL queries?

This tutorial demonstrates how to execute SQL queries from Python using the sqlite3 module. We'll cover establishing a connection, executing different types of queries (SELECT, INSERT, UPDATE, DELETE), and handling results. This knowledge is essential for any Python developer working with databases.

Establishing a Connection

First, we import the sqlite3 module. The sqlite3.connect() function establishes a connection to the database. If the database file ('mydatabase.db' in this case) doesn't exist, it will be created. A cursor object is then created using conn.cursor(). This cursor is used to execute SQL commands.

import sqlite3

# Connect to a database (or create it if it doesn't exist)
conn = sqlite3.connect('mydatabase.db')

# Create a cursor object to execute SQL queries
cursor = conn.cursor()

Creating a Table

This code creates a table named 'users' if it doesn't already exist. The table has three columns: 'id' (an integer and the primary key), 'name' (text, cannot be null), and 'age' (integer). The cursor.execute() method allows us to run SQL commands.

cursor.execute('''
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY,
        name TEXT NOT NULL,
        age INTEGER
    )
''')

Inserting Data

This section inserts two rows of data into the 'users' table. The cursor.execute() method is used to execute the INSERT statements. It's crucial to call conn.commit() to save the changes to the database. Without committing, the changes will not be persistent.

cursor.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)")
cursor.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)")

# Commit the changes to the database
conn.commit()

Executing a SELECT Query

This code executes a SELECT query to retrieve all rows from the 'users' table. The cursor.fetchall() method fetches all the results as a list of tuples, where each tuple represents a row. We then iterate through the results and print each row.

cursor.execute("SELECT * FROM users")

# Fetch all the results
results = cursor.fetchall()

for row in results:
    print(row)

Executing a SELECT Query with a WHERE Clause

This example demonstrates a SELECT query with a WHERE clause, filtering the results to only include users older than 27. We only select the 'name' and 'age' columns. The rest of the code is similar to the previous example, fetching and printing the results.

cursor.execute("SELECT name, age FROM users WHERE age > 27")

results = cursor.fetchall()

for row in results:
    print(row)

Executing an UPDATE Query

This code updates the age of the user named 'Alice' to 32. Remember to commit the changes after executing an UPDATE query.

cursor.execute("UPDATE users SET age = 32 WHERE name = 'Alice'")
conn.commit()

Executing a DELETE Query

This code deletes the user named 'Bob' from the table. Don't forget to commit the changes.

cursor.execute("DELETE FROM users WHERE name = 'Bob'")
conn.commit()

Closing the Connection

It's essential to close the database connection using conn.close() when you're finished with it. This releases resources and prevents potential issues.

conn.close()

Concepts Behind the Snippet

This snippet demonstrates basic CRUD (Create, Read, Update, Delete) operations using SQL queries. It uses the sqlite3 library, which provides a lightweight, disk-based database that doesn't require a separate server process. Understanding how to interact with databases using SQL queries is a fundamental skill for any software developer.

Real-Life Use Case

Imagine you're building a simple task management application. You can use a database to store task information (description, due date, status). The code snippets presented can be adapted to insert new tasks, retrieve tasks based on status, update task details, and delete completed tasks.

Best Practices

Use Parameterized Queries: Avoid SQL injection vulnerabilities by using parameterized queries instead of string formatting. For example: cursor.execute("SELECT * FROM users WHERE name = ?", (user_name,)).
Handle Exceptions: Wrap your database operations in try-except blocks to handle potential errors (e.g., database connection errors, incorrect SQL syntax).
Close Connections: Always close database connections when you're finished with them to release resources.

Interview Tip

Be prepared to discuss different types of SQL queries (SELECT, INSERT, UPDATE, DELETE) and their purpose. Also, understand the importance of using parameterized queries to prevent SQL injection. Be ready to explain how you would handle potential database errors.

When to Use Them

Use SQL queries when you need to store and manage structured data in a relational database. This is suitable for applications that require data persistence, complex relationships between data, and efficient querying capabilities.

Memory Footprint

The memory footprint depends on the size of the database and the amount of data being processed. For small to medium-sized databases, sqlite3 is generally efficient. For very large databases, consider using a more robust database system like PostgreSQL or MySQL.

Alternatives

Alternatives to sqlite3 include:
MySQL/MariaDB: Popular open-source relational database systems.
PostgreSQL: Another powerful open-source relational database system.
MongoDB: A NoSQL document database.
Object-Relational Mappers (ORMs): Libraries like SQLAlchemy that provide a higher-level abstraction for interacting with databases.

Pros

Simple to use: sqlite3 is easy to set up and use, requiring no separate server process.
Lightweight: It has a small footprint and is suitable for small to medium-sized applications.
Portable: The database is stored in a single file, making it easy to move and share.

Cons

Limited Concurrency: sqlite3 has limited support for concurrent access.
Scalability: Not suitable for very large databases or high-traffic applications.
Feature Set: Has a smaller feature set compared to more robust database systems like PostgreSQL or MySQL.

FAQ

  • How do I prevent SQL injection?

    Use parameterized queries. Instead of directly embedding variables into your SQL strings, use placeholders (e.g., ?) and pass the values as a separate tuple. The database driver will handle escaping the values properly.

  • What happens if I forget to commit my changes?

    If you forget to call conn.commit(), your changes will not be saved to the database. The data will revert to its previous state when the connection is closed.

  • How do I handle errors when executing SQL queries?

    Wrap your database operations in try-except blocks to catch potential exceptions (e.g., sqlite3.Error). Log the errors and handle them gracefully to prevent your application from crashing.