Operatori logici SQL - AND, OR, NOT e NULL senza errori

Gavino Caputo 27 maggio 2026
Tabelle di verità per operatori logici SQL: OR, AND, NOT. Mostra come combinare valori booleani.

Indice

Quando una query deve filtrare dati reali, una sola condizione spesso non basta. Capire gli operatori logici SQL permette di combinare criteri, gestire correttamente i valori mancanti e evitare risultati apparentemente inspiegabili. Qui mostro come usare AND, OR e NOT, come funzionano le parentesi, cosa cambia con NULL e quali errori possono rendere una query poco affidabile.

Le regole essenziali per costruire condizioni SQL corrette

  • AND richiede che tutte le condizioni siano vere.
  • OR restituisce una riga quando almeno una condizione è vera.
  • NOT nega una condizione, ma va usato con attenzione insieme a NULL.
  • Le parentesi rendono esplicito l’ordine di valutazione e prevengono filtri ambigui.
  • NULL non equivale a zero o a una stringa vuota e richiede IS NULL oppure IS NOT NULL.

Come funzionano AND, OR e NOT nelle query

Gli operatori logici collegano espressioni che producono un risultato logico. In una clausola WHERE, quel risultato decide se una riga viene mantenuta oppure esclusa. Per me, la distinzione più importante da imparare subito è questa: AND restringe il risultato, mentre OR lo amplia.

AND quando devono valere tutte le condizioni

Con AND, una riga passa il filtro solo se ogni condizione è vera. È il caso tipico di una ricerca per intervallo, categoria e stato contemporaneamente.

SELECT nome, città, fatturato
FROM clienti
WHERE regione = 'Lazio'
  AND fatturato >= 50000
  AND attivo = 1;

La query seleziona soltanto i clienti del Lazio con un fatturato almeno pari a 50.000 e con account attivo. Se anche una sola delle tre condizioni non è soddisfatta, la riga non appare. Questo rende AND utile per creare segmenti precisi, ma anche pericoloso quando si aggiungono filtri senza controllare quanto si riduce il numero di risultati.

OR quando basta una condizione

OR è adatto quando vuoi includere più alternative. Per esempio, puoi cercare ordini effettuati tramite il canale online oppure tramite l’applicazione mobile.

SELECT id_ordine, cliente_id, canale
FROM ordini
WHERE canale = 'web'
   OR canale = 'app';

Una riga viene restituita se almeno una delle due condizioni è vera. Quando le alternative riguardano lo stesso campo, spesso IN è più leggibile e più semplice da estendere.

SELECT id_ordine, cliente_id, canale
FROM ordini
WHERE canale IN ('web', 'app');

NOT per escludere un caso

NOT nega il risultato di una condizione. Può essere utile per eliminare i clienti inattivi o gli ordini già annullati.

SELECT *
FROM ordini
WHERE NOT stato = 'annullato';

In molti casi preferisco scrivere direttamente il confronto opposto, perché risulta più chiaro durante la manutenzione.

SELECT *
FROM ordini
WHERE stato <> 'annullato';

Le due forme non sono sempre equivalenti quando il campo può contenere NULL. È proprio questo il punto in cui la logica SQL si differenzia dalla logica booleana che usiamo nella vita quotidiana.

Perché NULL produce risultati inattesi

In SQL, NULL indica che un valore è mancante, sconosciuto o non applicabile. Non significa automaticamente zero, stringa vuota o falso. Una comparazione come prezzo = NULL non restituisce vero, perché il database non può stabilire che un valore sconosciuto sia uguale a un altro valore sconosciuto.

La logica a tre valori

Le condizioni SQL possono produrre tre risultati: TRUE, FALSE oppure UNKNOWN. Quest’ultimo compare spesso quando una condizione coinvolge NULL.

Condizione Risultato Interpretazione
TRUE AND TRUE TRUE Entrambe le condizioni sono soddisfatte
TRUE AND UNKNOWN UNKNOWN Una condizione non è determinabile
FALSE AND UNKNOWN FALSE È già sufficiente una condizione falsa
TRUE OR UNKNOWN TRUE La prima condizione è già sufficiente
FALSE OR UNKNOWN UNKNOWN Non c’è ancora una condizione vera
NOT UNKNOWN UNKNOWN Il valore sconosciuto resta non determinabile

La clausola WHERE conserva soltanto le righe per cui la condizione è TRUE. Le righe con risultato FALSE o UNKNOWN vengono escluse. Questa regola spiega perché una query può restituire meno record del previsto senza mostrare un errore.

Come verificare correttamente i valori mancanti

Per cercare i valori mancanti devi usare IS NULL o IS NOT NULL.

SELECT id, email
FROM clienti
WHERE email IS NULL;

Per escludere i record senza email:

SELECT id, email
FROM clienti
WHERE email IS NOT NULL;

Questo dettaglio sembra elementare, ma nella pratica è uno degli errori più frequenti. Quando controllo query scritte da chi sta iniziando, trovo spesso = NULL al posto di IS NULL, con il risultato di ottenere una tabella vuota.

Le parentesi decidono il significato della query

Quando AND e OR compaiono nella stessa condizione, il database valuta normalmente AND prima di OR. Non affidarti però alla memoria o all’intenzione implicita. Le parentesi rendono il significato evidente a chi legge e riducono il rischio di filtrare dati sbagliati.

SELECT *
FROM prodotti
WHERE categoria = 'Laptop'
   OR categoria = 'Tablet'
  AND prezzo < 1000;

Questa condizione viene interpretata come:

categoria = 'Laptop'
OR (categoria = 'Tablet' AND prezzo < 1000)

Di conseguenza, tutti i laptop vengono inclusi, anche quelli più costosi, mentre solo i tablet sotto i 1.000 euro passano il filtro. Se l’obiettivo era applicare il limite di prezzo a entrambe le categorie, la forma corretta è:

SELECT *
FROM prodotti
WHERE (categoria = 'Laptop' OR categoria = 'Tablet')
  AND prezzo < 1000;

La differenza può cambiare radicalmente il risultato. In un report commerciale, un errore simile può gonfiare vendite, margini o numero di clienti. Io uso le parentesi anche quando il motore SQL potrebbe interpretare correttamente la query senza di esse, perché la leggibilità è parte della qualità tecnica.

Una regola pratica per evitare ambiguità

Raggruppa sempre le alternative con OR e applica dopo i vincoli comuni con AND. Questo schema è facile da controllare:

WHERE (condizione_alternativa_1 OR condizione_alternativa_2)
  AND condizione_comune;

La stessa attenzione serve con NOT. Per esempio, queste due condizioni non hanno lo stesso significato:

WHERE NOT stato = 'chiuso' OR priorità = 'alta';
WHERE NOT (stato = 'chiuso' OR priorità = 'alta');

Nel primo caso puoi includere una pratica chiusa se ha priorità alta. Nel secondo caso escludi tutte le righe chiuse o ad alta priorità. Una coppia di parentesi può trasformare completamente una regola di business.

Operatori di confronto e condizioni composte

Gli operatori logici raramente lavorano da soli. Di solito collegano confronti come =, <>, >, >=, LIKE, BETWEEN e IN. La combinazione corretta dipende dal tipo di domanda che vuoi fare ai dati.

Operatore Uso tipico Esempio
= Uguaglianza esatta stato = 'attivo'
<> Esclusione di un valore stato <> 'annullato'
BETWEEN Intervallo inclusivo prezzo BETWEEN 100 AND 500
IN Elenco di valori ammessi regione IN ('Lazio', 'Lombardia')
LIKE Ricerca parziale su testo email LIKE '%@azienda.it'
IS NULL Ricerca di valori mancanti telefono IS NULL

Un esempio realistico può combinare più strumenti:

SELECT id, nome, città
FROM clienti
WHERE (città IN ('Roma', 'Milano', 'Torino'))
  AND attivo = 1
  AND email IS NOT NULL;

La query cerca clienti attivi di tre città che hanno un indirizzo email disponibile. Il vantaggio non è solo sintattico: ogni parte esprime una scelta precisa sul dataset e rende il filtro più facile da verificare.

Il caso particolare di BETWEEN

BETWEEN include entrambi gli estremi dell’intervallo. La condizione prezzo BETWEEN 100 AND 500 comprende quindi anche i valori 100 e 500. Con date e orari bisogna essere più cauti, perché un filtro come BETWEEN '2026-01-01' AND '2026-01-31' può escludere parte dell’ultimo giorno se la colonna contiene anche l’orario.

Per intervalli temporali, spesso è più sicuro usare un limite inferiore incluso e uno superiore escluso:

WHERE data_evento >= '2026-01-01'
  AND data_evento < '2026-02-01';

Questo approccio evita di dover indovinare l’ultimo istante della giornata e funziona bene anche quando il campo memorizza ore, minuti e secondi.

Errori frequenti e prestazioni delle condizioni

Una query logicamente corretta può comunque essere lenta o difficile da mantenere. Il primo errore che controllo è l’uso eccessivo di OR senza parentesi, seguito da confronti incoerenti tra numeri, date e stringhe.

  • Confondere AND con OR può restituire troppe righe oppure nessuna riga.
  • Usare = NULL impedisce di trovare i valori mancanti.
  • Negare una condizione senza parentesi può estendere l’esclusione oltre il previsto.
  • Applicare funzioni alla colonna, come YEAR(data_evento), può rendere più difficile usare un indice.
  • Usare LIKE con un carattere jolly iniziale, come LIKE '%roma', può ridurre l’efficacia degli indici.

Non dare per scontato che il database valuti le condizioni esattamente nell’ordine in cui le hai scritte. Il motore può scegliere un piano di esecuzione diverso per migliorare i tempi, quindi non usare l’ordine delle condizioni come protezione contro divisioni per zero o dati non validi.

Per verificare l’effetto reale di un filtro, usa il piano di esecuzione con strumenti come EXPLAIN o l’equivalente del tuo database. Un indice sulla colonna filtrata può aiutare molto, ma non risolve ogni caso. La selettività del filtro, la quantità di dati e la forma della query contano altrettanto.

Leggi anche: Relazione molti a molti - tabella ponte e query SQL

XOR e simboli alternativi

Alcuni sistemi, tra cui MySQL, supportano anche XOR, che è vero quando una sola delle due condizioni è vera. Non è però un operatore da usare alla cieca in query destinate a database diversi, perché il supporto e la sintassi possono cambiare.

SELECT *
FROM utenti
WHERE newsletter = 1 XOR notifiche_sms = 1;

In una query portabile preferisco spesso esprimere lo stesso concetto con AND, OR e NOT, anche se la formula è più lunga:

WHERE (newsletter = 1 AND notifiche_sms <> 1)
   OR (newsletter <> 1 AND notifiche_sms = 1);

Anche simboli come &&, || e ! non sono una buona scelta per il codice SQL condiviso tra più sistemi. Le parole chiave AND, OR e NOT sono più leggibili e riducono i problemi legati al dialetto utilizzato.

La regola che rende affidabili le tue condizioni SQL

Quando costruisco un filtro, parto dalla domanda in linguaggio naturale e la trasformo in blocchi semplici. Prima individuo le alternative, poi raggruppo quelle con OR, infine applico con AND i vincoli che devono valere sempre.

Controllo anche la presenza di NULL e provo la query su casi limite, come date agli estremi, campi vuoti e valori inattesi. Bastano pochi test mirati per scoprire errori che una tabella di risultati apparentemente corretta potrebbe nascondere.

La sintassi conta, ma conta ancora di più il significato del filtro. Parentesi esplicite, gestione corretta di NULL e condizioni brevi rendono le query più leggibili, portabili e affidabili nei report e nei progetti di analisi dati.

Domande frequenti

SQL valuta normalmente AND prima di OR. Per applicare un vincolo comune a più alternative, raggruppa le condizioni con OR tra parentesi e collegale poi con AND, come in WHERE (categoria = 'Laptop' OR categoria = 'Tablet') AND prezzo < 1000.

NULL rappresenta un valore mancante o sconosciuto e il confronto = NULL produce UNKNOWN, non TRUE. Per cercare i valori mancanti devi usare IS NULL, mentre per escluderli devi usare IS NOT NULL; la clausola WHERE conserva solo le righe con risultato TRUE.

NOT e il confronto <> non vanno considerati sempre equivalenti quando la colonna può contenere NULL. Le condizioni che coinvolgono NULL possono produrre UNKNOWN, quindi per gestire esplicitamente i valori mancanti è necessario usare IS NULL o IS NOT NULL.

BETWEEN include entrambi gli estremi, ma un limite scritto come BETWEEN '2026-01-01' AND '2026-01-31' può escludere parte del 31 gennaio se la colonna contiene anche l’orario. Per gli intervalli temporali è spesso più sicuro usare >= '2026-01-01' AND < '2026-02-01'.

Tra gli errori più comuni ci sono l’uso di OR senza parentesi, l’applicazione di funzioni alla colonna, come YEAR(data_evento), e i caratteri jolly iniziali in LIKE, come LIKE '%roma'. Per valutare l’effetto reale del filtro puoi esaminare il piano di esecuzione con EXPLAIN o con lo strumento equivalente del database.

Valuta l'articolo

Valutazione: 0.00 Numero di voti: 0

Tag

sql
operatori logici
null
precedenza
indicizzazione
Autor Gavino Caputo
Gavino Caputo
Mi chiamo Gavino Caputo e da 14 anni mi occupo con passione di analisi dati, Business Intelligence e Data Science. Ho iniziato questo percorso perché sono sempre stato affascinato dalla possibilità di trasformare grandi volumi di informazioni in conoscenza utile e fruibile. Sul sito mondobi.it, il mio obiettivo è quello di rendere accessibili concetti complessi, condividendo la mia esperienza per aiutare a comprendere meglio il mondo dei dati, le sue applicazioni e le tendenze emergenti. Cerco di fornire contenuti accurati e aggiornati, spiegando i temi in modo chiaro e strutturato, basandomi su un confronto costante tra le diverse fonti e metodologie che incontro nel mio lavoro quotidiano.

Condividi post

Scrivi un commento