Explain Codes LogoExplain Codes Logo

Python: Number of rows affected by cursor.execute("SELECT ...")

python
sql-injection
parametrized-queries
fetch-strategy
Nikita BarsukovbyNikita Barsukov·Nov 3, 2024
TLDR

Retrieve the row count after a SELECT query by utilizing cursor.rowcount just after cursor.execute(). Here it is in action:

cursor.execute("SELECT * FROM table") print(f"Rows fetched: {cursor.rowcount}")

Note: If cursor.rowcount gives -1 or None, it signifies that the count is unavailable. This behavior varies with the database driver in use.

Observing query safety

When issuing SELECT statements, consider personal safety. Just like you wouldn't go out without a helmet, don't open your program to SQL injection. Use parametrized queries like below:

query = "SELECT * FROM users WHERE username = %s" cursor.execute(query, ('example_user',)) # Yes, like a bike helmet for SQL queries

Place your trust in placeholders such as %s or %(key)s, and let the DB adapter deal with the quoting and escaping.

Getting row count efficiently

There could be times when you want the count but are in no mood to fetch all rows. Say you're tired, it's been a long day. You can do this:

  • Just do fetchone() on a COUNT query:
cursor.execute("SELECT COUNT(*) FROM table") print(f"Rows counted: {cursor.fetchone()[0]}") # Count without a headache

For more than one result, fetchall() or fetchmany(size) are your friends, with len() ready to reveal the count.

Adapting to your environment

Different strokes for different folks. Understand the parametrized arguments syntax that clicks with your Python/DB adapter. Below is an example for sqlite3:

query = "SELECT * FROM users WHERE username = ?" cursor.execute(query, ('example_user',)) # It's like the way you mix a cocktail, depends on what you're mixing

Steering through common issues

Trusting rowcount

cursor.rowcount may be not everyone's cup of tea. Its behavior has no guarantee by the DB API. Always take a quick look at your database driver's documentation.

Handling the big fish

When you face large datasets, using fetchall() may overwhelm you. Think memory and processing. Use fetchone() or fetchmany() in loops to process results in portions:

while True: row = cursor.fetchone() if row is None: break process_row(row) # Friendlier to your memory and server

Knowing your tools

Different databases offer various cursor types, such as server-side or client-side. This choice can affect the rowcount.

Staying informed

Stay alert to future DB API changes. Like new tax rules, these might affect how rowcount operates or what it returns when the count is undefined.

Embracing the unknown

Understanding rowcount variation

Different database adapters may define rowcount differently, especially after a SELECT statement. Be agile and always check your adapter's documentation.

Crafting secure SQL strings

Be vigilant when string concatenation is involved, as it can pave way for SQL injection attacks. Stay safe and use parametrized queries.

Choosing the right fetch strategy

Depending on your use case and resources, choose between fetchone(), fetchmany(), or fetchall() - like picking the right horse for the race.