SQL with Python: sqlite3, pandas and SQLAlchemy Basics

Part 5 of the Python for Data Science track. Last updated: September 2026.

Most data lives in databases, not CSVs. Python talks to SQL databases natively via sqlite3 (built in, zero setup — perfect for learning) and scales up with pandas and SQLAlchemy.

Connecting and creating a table

import sqlite3

conn = sqlite3.connect("shop.db")   # creates the file if it doesn't exist
cur = conn.cursor()

cur.execute("""CREATE TABLE IF NOT EXISTS customers (
    id INTEGER PRIMARY KEY, name TEXT, city TEXT)""")
conn.commit()

Inserting safely: parameterized queries

# ? placeholders — values travel SEPARATELY from the SQL text
cur.execute("INSERT INTO customers (name, city) VALUES (?, ?)", ("Ada", "London"))
cur.execute("INSERT INTO customers (name, city) VALUES (?, ?)", ("Grace", "New York"))
conn.commit()

# NEVER build SQL with f-strings: f"SELECT ... WHERE city = '{city}'"
# invites SQL injection. Placeholders are non-negotiable.

Querying

cur.execute("SELECT * FROM customers WHERE city = ?", ("London",))
print(cur.fetchall())          # [(1, 'Ada', 'London')]

for row in cur.execute("SELECT name FROM customers ORDER BY name"):
    print(row[0])              # rows are tuples — index into them

pandas and SQL: read_sql_query and to_sql

import pandas as pd

# SQL result straight into a DataFrame
df = pd.read_sql_query(
    "SELECT city, COUNT(*) AS n FROM customers GROUP BY city", conn)
print(df)

# DataFrame straight into a table
orders = pd.DataFrame({"customer_id": [1, 1, 2], "amount": [50, 75, 120]})
orders.to_sql("orders", conn, if_exists="replace", index=False)

joined = pd.read_sql_query(
    """SELECT c.name, o.amount FROM customers c
       JOIN orders o ON c.id = o.customer_id""", conn)
print(joined)
conn.close()

This two-way bridge — SQL for filtering at the source, pandas for analysis — is how production data work actually looks.

A taste of SQLAlchemy

For larger apps, SQLAlchemy is the standard toolkit (install with pip install sqlalchemy). Same database, richer API:

from sqlalchemy import create_engine, text

engine = create_engine("sqlite:///shop.db")   # works for Postgres/MySQL too — just change the URL
with engine.connect() as c:
    rows = c.execute(text("SELECT name FROM customers WHERE city = :city"),
                     {"city": "London"}).fetchall()
print(rows)

Key takeaways

  • sqlite3 is built in — zero-setup SQL for learning and prototypes.
  • Always use parameterized queries (? or :name); never f-strings for values.
  • read_sql_query / to_sql bridge SQL and pandas in both directions.
  • SQLAlchemy is the production-grade layer when you outgrow raw sqlite3.

Next in this series: Exploratory Data Analysis: A Complete Walkthrough.

Comments

Popular posts from this blog

Java Banking Finance Services and Insurance (BFSI) domain interview questions

JSP Servlet Interview Questions For Freshers Series 1

Java program to check even or odd number