Eseguire query SQL da Pandas
Esegua istruzioni SELECT arbitrarie con pd.read_sql_query e parametrizzi le query in modo sicuro per evitare l'SQL injection.
Eseguire query SQL da Pandas è una lezione Pandas & NumPy Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Pandas & NumPy Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Pandas & NumPy Academy include 4 lezioni in totale.
pd.read_sql: l'interfaccia unificata
Pandas fornisce tre funzioni per la lettura da SQL: pd.read_sql() (wrapper generico), pd.read_sql_table() (legge una tabella completa tramite il nome) e pd.read_sql_query() (esegue SQL arbitrario). Per la maggior parte dei flussi di lavoro analitici, pd.read_sql_query() è la soluzione più potente perché consente di scrivere qualsiasi istruzione SELECT con filtri, join e aggregazioni prima che i dati arrivino in Pandas. Usare SQL per le operazioni più pesanti e Pandas per l'analisi finale è spesso più efficiente che caricare tutto e filtrare in Python.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///ecommerce.db')
# Three equivalent patterns
df1 = pd.read_sql('SELECT * FROM orders LIMIT 100', con=engine)
df2 = pd.read_sql_table('orders', con=engine) # full table
df3 = pd.read_sql_query('SELECT * FROM orders LIMIT 100', con=engine)
print(df3.head())
print(df3.columns.tolist())Filtrare a livello di database
Filtri sempre i dati in SQL invece di caricare tutto e filtrare in Pandas. Un database con indici appropriati può eseguire una clausola WHERE su milioni di righe e restituirne solo alcune migliaia in pochi millisecondi, mentre Pandas dovrebbe prima caricare gigabyte di dati. La regola d'oro è: sposti i predicati nel database. Usi WHERE per filtrare le righe, SELECT col1, col2 per selezionare le colonne e LIMIT durante lo sviluppo per visualizzare rapidamente un'anteprima dei risultati.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
# Filter and project at SQL level — only fetch what you need
query = '''
SELECT order_id, customer_id, amount, status
FROM orders
WHERE status = 'completed'
AND order_date >= '2024-01-01'
AND amount > 50
LIMIT 1000
'''
df = pd.read_sql_query(query, con=engine)
print(f'Rows: {len(df)}, Columns: {list(df.columns)}')Aggregare in SQL o in Pandas
Per semplici riepiloghi a livello di gruppo su tabelle di grandi dimensioni, le aggregazioni SQL sono più efficienti di Pandas perché il motore del database può usare indici, esecuzione parallela e aggregazione hash su disco. Usi SQL per GROUP BY e SUM/COUNT/AVG quando la tabella è grande. Carichi il risultato aggregato (un piccolo DataFrame) in Pandas per ulteriori analisi, visualizzazioni o combinazioni con altri dati. Per aggregazioni personalizzate complesse che SQL non è in grado di esprimere, carichi un sottoinsieme filtrato in Pandas e usi groupby.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
# Aggregate in SQL — returns a small result set
query = '''
SELECT region,
COUNT(*) AS order_count,
ROUND(SUM(amount), 2) AS total_revenue,
ROUND(AVG(amount), 2) AS avg_order_value
FROM orders
WHERE status = 'completed'
GROUP BY region
ORDER BY total_revenue DESC
'''
df = pd.read_sql_query(query, con=engine)
print(df)JOIN nelle query SQL
Le operazioni SQL di tipo JOIN sono più efficienti di merge() di Pandas per i join su tabelle di grandi dimensioni, perché il database può usare ricerche indicizzate. Scriva il join in SQL e riceva in Pandas un risultato già unito e potenzialmente filtrato. Per le analisi su più tabelle, una singola query SQL con più JOIN è generalmente più veloce che leggere ogni tabella separatamente e unirle in Pandas, soprattutto quando una tabella contiene milioni di righe e il join riduce significativamente il risultato.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///ecommerce.db')
query = '''
SELECT o.order_id,
c.customer_name,
c.country,
p.product_name,
o.amount
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN products p ON o.product_id = p.id
WHERE o.status = 'completed'
LIMIT 500
'''
df = pd.read_sql_query(query, con=engine)
print(df.head())Usare variabili Python nelle query
Per inserire in modo sicuro variabili Python nelle query SQL, usi text() di SQLAlchemy con parametri denominati. Definisca i segnaposto con :param_name nella stringa della query e passi un dizionario all'argomento params di read_sql_query. Questa tecnica funziona sia per singoli valori sia, con alcuni database, per le liste. Eviti le f-string o la formattazione con % per costruire stringhe di query a partire da variabili: non sono sicure, nemmeno per l'uso interno.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
# Python variables to inject
min_amount = 200.0
start_date = '2024-01-01'
end_date = '2024-12-31'
query = sa.text('''
SELECT * FROM orders
WHERE amount > :min_amount
AND order_date BETWEEN :start_date AND :end_date
''')
with engine.connect() as conn:
df = pd.read_sql_query(query, con=conn,
params={'min_amount': min_amount,
'start_date': start_date,
'end_date': end_date})
print(f'{len(df)} orders found')Usare CTE e sottoquery
Le analisi complesse spesso richiedono Common Table Expressions (CTE) o sottoquery. Sono pienamente supportate da pd.read_sql_query: passi semplicemente l'intera istruzione SQL con più clausole come stringa della query. Le CTE (introdotte dalla parola chiave WITH) rendono più leggibili le query complesse dando un nome ai risultati intermedi. Sono utili per calcolare totali progressivi, creare classifiche all'interno dei gruppi ed eseguire filtri in più passaggi che in Pandas risulterebbero prolissi.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
query = '''
WITH monthly_revenue AS (
SELECT strftime('%Y-%m', order_date) AS month,
SUM(amount) AS revenue
FROM orders
WHERE status = 'completed'
GROUP BY month
)
SELECT month,
revenue,
revenue - LAG(revenue) OVER (ORDER BY month)
AS month_over_month_change
FROM monthly_revenue
ORDER BY month
'''
df = pd.read_sql_query(query, con=engine)
print(df.tail())Leggere con un DatetimeIndex
Quando legge dati di serie temporali da un database, imposti la colonna timestamp come indice del DataFrame passando index_col='date_column' e parse_dates=['date_column'] a read_sql_query. In questo modo ottiene direttamente un DatetimeIndex, che consente di usare il sezionamento temporale di Pandas (df['2024-01']), il ricampionamento e i calcoli su finestre mobili senza ulteriori passaggi di post-elaborazione. L'argomento parse_dates indica a Pandas di convertire la colonna in datetime64.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///metrics.db')
df = pd.read_sql_query(
'SELECT recorded_at, metric_value FROM daily_metrics ORDER BY recorded_at',
con=engine,
index_col='recorded_at',
parse_dates=['recorded_at']
)
print(df.index.dtype) # datetime64[ns]
print(df['2024-06']) # Slice by month directlyAnalizzare le prestazioni delle query lente
Quando una query è lenta, aggiunga la parola chiave SQL EXPLAIN (o EXPLAIN QUERY PLAN in SQLite) prima della SELECT per visualizzare il piano di esecuzione del database. Cerchi scansioni complete delle tabelle ('SCAN TABLE') dove si aspetterebbe ricerche tramite indice ('SEARCH TABLE'). Gli indici mancanti sulle colonne usate in WHERE e JOIN sono la causa più comune delle query lente. Crei l'indice appropriato nel database e verifichi nuovamente con EXPLAIN prima di eseguire di nuovo la pipeline Pandas.
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
# Check if the query uses an index
with engine.connect() as conn:
plan = conn.execute(sa.text(
'EXPLAIN QUERY PLAN SELECT * FROM orders WHERE customer_id = 42'
)).fetchall()
for row in plan:
print(row)
# Look for 'SEARCH TABLE orders USING INDEX' — not 'SCAN TABLE'Paginazione di grandi set di risultati
Quando si scorre interattivamente un set di risultati di grandi dimensioni (ad esempio, elaborando una pagina di risultati alla volta), utilizzi SQL LIMIT e OFFSET per implementare la paginazione. Recuperi N righe alla volta, le elabori, quindi recuperi le N successive. Sebbene sia meno efficiente dell'approccio con chunksize (che mantiene un cursore), la paginazione è utile quando le righe devono essere visualizzate progressivamente in un report o quando si combinano risultati provenienti da più query.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
page_size = 10000
offset = 0
while True:
query = sa.text(
'SELECT * FROM orders ORDER BY order_id LIMIT :limit OFFSET :offset'
)
with engine.connect() as conn:
df = pd.read_sql_query(query, con=conn,
params={'limit': page_size, 'offset': offset})
if len(df) == 0:
break
print(f'Page at offset {offset}: {len(df)} rows')
offset += page_sizeCombinare query SQL con la logica Pandas
Il pattern più potente è una pipeline ibrida: utilizzi SQL per il filtraggio e l'aggregazione a grana grossa, quindi Pandas per le trasformazioni a grana fine che SQL esprime in modo poco agevole (tabelle pivot, analisi di stringhe, funzioni apply, finestre mobili). Legga da SQL un set di risultati gestibile (migliaia di righe), quindi concateni le operazioni Pandas sul DataFrame risultante. In questo modo combina i punti di forza di entrambi gli strumenti, mantenendo i dati all'interno di un unico processo Python.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
# SQL: coarse filter and join
df = pd.read_sql_query('''
SELECT o.customer_id, o.amount, o.order_date, c.country
FROM orders o JOIN customers c ON o.customer_id = c.id
WHERE o.status = 'completed'
''', con=engine, parse_dates=['order_date'])
# Pandas: rolling 30-day revenue per country
df = df.sort_values('order_date')
df['rolling_30d'] = (
df.groupby('country')['amount']
.transform(lambda x: x.rolling('30D').sum())
)
print(df.head())Gestione degli errori nelle query del database
Le query del database possono fallire a causa di timeout di rete, errori di sintassi o connessioni interrotte. Racchiuda le chiamate al database in blocchi try-except che intercettino sqlalchemy.exc.OperationalError per i problemi di connessione e sqlalchemy.exc.ProgrammingError per gli errori di sintassi SQL. Registri l'errore insieme al contesto (query, parametri) e riprovi con un backoff esponenziale oppure gestisca il fallimento in modo corretto. Nelle pipeline di produzione, distinguere gli errori transitori (per i quali è possibile riprovare) da quelli permanenti (che richiedono la correzione dell'SQL) è essenziale.
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///sales.db')
try:
df = pd.read_sql_query(
'SELECT * FROM nonexistent_table',
con=engine
)
except sa.exc.OperationalError as e:
print(f'Connection or table error: {e}')
except sa.exc.ProgrammingError as e:
print(f'SQL syntax error: {e}')
except Exception as e:
print(f'Unexpected error: {type(e).__name__}: {e}')Verifica rapida
Verifichi la comprensione dei concetti di analisi dei dati trattati in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato che: pd.read_sql_query() esegue qualsiasi SELECT SQL e restituisce un DataFrame; spostare filtri e aggregazioni in SQL è più efficiente che caricare intere tabelle in Pandas; e le pipeline ibride combinano SQL per la riduzione dei dati a grana grossa con Pandas per le trasformazioni personalizzate a grana fine. Ora vedremo come riscrivere i DataFrame nelle tabelle del database.
Domande Frequenti
La lezione «Eseguire query SQL da Pandas» è gratuita?
Sì — il testo completo di «Eseguire query SQL da Pandas» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Pandas & NumPy Academy, passa a CoddyKit PRO. Il corso Pandas & NumPy Academy include 4 lezioni in totale.
Cosa imparerò in «Eseguire query SQL da Pandas»?
Esegua istruzioni SELECT arbitrarie con pd.read_sql_query e parametrizzi le query in modo sicuro per evitare l'SQL injection. Eserciti Pandas & NumPy Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Pandas & NumPy Academy?
Non è richiesta alcuna esperienza precedente. Pandas & NumPy Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Eseguire query SQL da Pandas»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Pandas & NumPy Academy?
Sì. Ogni lezione Pandas & NumPy Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Connettersi a un database con SQLAlchemy
- Eseguire query SQL da Pandas
- Scrivere DataFrame nelle tabelle del database
- Pandas o SQL: scegliere lo strumento giusto