Python sqlite3.Row.keys Method
Last modified April 15, 2025
This comprehensive guide explores Python's sqlite3.Row.keys method,
which provides access to column names in query results. We'll cover basic usage,
practical examples, and integration with database operations.
Basic Definitions
The sqlite3.Row.keys method returns a list of column names from a
query result row. It's available when using sqlite3.Row as the row
factory for a connection.
Key characteristics: it provides ordered column names matching the query, enables named access to row data, and works with both simple and complex queries. The method is essential for dynamic SQL handling.
Basic Row.keys Usage
Here's the simplest usage of sqlite3.Row.keys to get column names
from a query result.
import sqlite3
with sqlite3.connect(':memory:') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute('''CREATE TABLE users
(id INTEGER PRIMARY KEY, name TEXT, email TEXT)''')
cursor.execute("INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')")
cursor.execute("SELECT * FROM users")
row = cursor.fetchone()
print(row.keys()) # Output: ['id', 'name', 'email']
This example creates an in-memory database with a simple table. After setting
sqlite3.Row as the row factory, we fetch one row and print its
column names.
The output shows the column names in the order they were defined in the table,
demonstrating how keys provides metadata about the result structure.
Using Keys with Dynamic Queries
The keys method is particularly useful when working with dynamic
queries where column names aren't known in advance.
import sqlite3
def print_query_results(conn, query):
cursor = conn.cursor()
cursor.execute(query)
for row in cursor:
print("Columns:", row.keys())
for col in row.keys():
print(f"{col}: {row[col]}")
print()
with sqlite3.connect(':memory:') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute('''CREATE TABLE products
(id INTEGER PRIMARY KEY, name TEXT, price REAL)''')
cursor.executemany("INSERT INTO products (name, price) VALUES (?, ?)",
[('Laptop', 999.99), ('Phone', 699.99)])
print_query_results(conn, "SELECT * FROM products")
print_query_results(conn, "SELECT name, price FROM products WHERE price > 700")
This example demonstrates a reusable function that prints query results along
with their column names. The keys method allows the function to
work with any query without knowing its structure beforehand.
The output shows different column sets for different queries, proving the flexibility of this approach when dealing with dynamic SQL.
Building Dictionaries from Rows
We can combine keys with dictionary comprehension to convert rows
into dictionaries with column names as keys.
import sqlite3
with sqlite3.connect(':memory:') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute('''CREATE TABLE employees
(id INTEGER, name TEXT, department TEXT, salary REAL)''')
cursor.execute('''INSERT INTO employees VALUES
(1, 'John Smith', 'Engineering', 85000)''')
cursor.execute("SELECT * FROM employees")
row = cursor.fetchone()
# Convert row to dictionary
row_dict = {key: row[key] for key in row.keys()}
print(row_dict)
# Output: {'id': 1, 'name': 'John Smith', 'department': 'Engineering', 'salary': 85000.0}
This example shows how to transform a sqlite3.Row object into a
regular dictionary. The keys method provides the dictionary keys.
This technique is useful when you need to serialize database rows or pass them to functions that expect dictionaries rather than row objects.
Validating Column Names
The keys method can help validate that a query returned the
expected columns before processing the data.
import sqlite3
def validate_columns(row, expected_columns):
actual_columns = row.keys()
if set(expected_columns) != set(actual_columns):
raise ValueError(f"Expected columns {expected_columns}, got {actual_columns}")
with sqlite3.connect(':memory:') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute('''CREATE TABLE inventory
(item_id INTEGER, name TEXT, quantity INTEGER)''')
cursor.execute('''INSERT INTO inventory VALUES
(101, 'Widget', 50)''')
cursor.execute("SELECT item_id, name, quantity FROM inventory")
row = cursor.fetchone()
try:
validate_columns(row, ['item_id', 'name', 'quantity'])
print("Column validation passed")
except ValueError as e:
print("Column validation failed:", e)
This example demonstrates a validation function that checks if a row contains
the expected columns. The keys method provides the actual column
names for comparison.
Such validation is particularly valuable in applications where query results must conform to specific schemas or when working with dynamically generated SQL.
Handling Aliased Columns
The keys method reflects column aliases used in SQL queries,
showing exactly what names are available in the result set.
import sqlite3
with sqlite3.connect(':memory:') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute('''CREATE TABLE orders
(order_id INTEGER, customer TEXT, total REAL)''')
cursor.execute('''INSERT INTO orders VALUES
(1001, 'Acme Corp', 1250.75)''')
# Query with column aliases
cursor.execute('''SELECT
order_id AS id,
customer AS client,
total AS amount
FROM orders''')
row = cursor.fetchone()
print("Column names:", row.keys())
# Output: Column names: ['id', 'client', 'amount']
# Access using aliases
print(f"Order {row['id']} for {row['client']}: ${row['amount']}")
This example shows how column aliases in SQL queries affect the names returned by
keys. The method provides the aliased names, not the original
column names from the table.
This behavior is important to understand when working with complex queries that rename columns for clarity or compatibility with application code.
Working with Joined Tables
When querying multiple tables with joins, keys shows all available
columns, including duplicate names from different tables.
import sqlite3
with sqlite3.connect(':memory:') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# Create two related tables
cursor.execute('''CREATE TABLE departments
(id INTEGER, name TEXT)''')
cursor.execute('''CREATE TABLE employees
(id INTEGER, name TEXT, dept_id INTEGER)''')
# Add sample data
cursor.execute("INSERT INTO departments VALUES (1, 'Engineering')")
cursor.execute("INSERT INTO employees VALUES (101, 'Alice', 1)")
# Query with join
cursor.execute('''SELECT e.id AS emp_id, e.name AS emp_name,
d.id AS dept_id, d.name AS dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.id''')
row = cursor.fetchone()
print("Column names:", row.keys())
# Output: Column names: ['emp_id', 'emp_name', 'dept_id', 'dept_name']
# Access specific columns
print(f"{row['emp_name']} works in {row['dept_name']}")
This example demonstrates how keys handles column names from
joined tables. We use explicit aliases to avoid ambiguity in the result set.
The method shows all available columns after the join, with names reflecting our aliases. This makes it clear which columns come from which tables.
Advanced: Dynamic Data Processing
For maximum flexibility, we can use keys to process query results
without any prior knowledge of the table structure.
import sqlite3
from tabulate import tabulate
def execute_and_display(conn, query):
cursor = conn.cursor()
cursor.execute(query)
if cursor.description is None:
print("No results to display")
return
# Get all rows
rows = cursor.fetchall()
if not rows:
print("No rows returned")
return
# Display as table
headers = rows[0].keys()
data = [[row[col] for col in headers] for row in rows]
print(tabulate(data, headers=headers, tablefmt="grid"))
with sqlite3.connect(':memory:') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# Create sample data
cursor.execute('''CREATE TABLE sales
(region TEXT, product TEXT, amount REAL, quarter INTEGER)''')
cursor.executemany("INSERT INTO sales VALUES (?, ?, ?, ?)",
[('West', 'A', 1000, 1),
('East', 'B', 1500, 1),
('North', 'A', 800, 2)])
# Display different queries
execute_and_display(conn, "SELECT * FROM sales")
execute_and_display(conn, "SELECT region, SUM(amount) AS total FROM sales GROUP BY region")
This advanced example shows a generic function that can execute any query and
display the results in a formatted table. The keys method
provides the column headers automatically.
The function handles different query types (simple selects, aggregates) without modification, demonstrating the power of dynamic column name access.
Best Practices
- Use Row factory: Always set
row_factory=sqlite3.Rowfor named access - Prefer named access: Use
row['column']instead of positional access - Handle case sensitivity: Column names in
keyspreserve case - Cache column lists: Store
keysresults if reused frequently - Combine with description: Use
cursor.descriptionfor more metadata
Source References
Author
List all Python tutorials.