Intanto m a m significa una relazione molti a molti.
In soldoni, sono due relazioni uno a molti in due sensi di lettura.
in pratica hai due relazioni:
prima relazione 1 a M con tabellaA (lato 1) a TabellaB (lato Molti)
seconda relazione 1 a M con tabellaB (lato 1) a TabellaA (lato Molti)
considerando che ina corsa può essere svolta da più autisti e che ogni autista può effettuare più corse la tua relazione è M a M.
Vuoi sapere quali dati della tabella di partenza (tabellaA) sono assegnate e quindi presenti nella relazione (tabellaC)
Vuoi sapere quali dati della Tabella di partenza NON sono state assegnate
puoi procedere in 2 modi: Con NOT EXISTS oppure con LEFT JOIN ... IS NULL
Supponiamo di avere:
Tabella A
id_a | nome
---------------
1 | Rossi
2 | Verdi
Tabella B
id_b | descrizione
---------------------
10 | X
20 | Y
30 | Z
40 | W
Tabella C relazione molti-a-molti (m a m) tra A e B
id_a | id_b
--------------
1 | 10
1 | 20
2 | 30
In questo caso il valore 40 della tabella B non è presente nella relazione C.
caso 1. Con NOT EXISTS
SELECT b.*
FROM B b
WHERE NOT EXISTS (
SELECT 1
FROM C c
WHERE c.id_b = b.id_b
);
Risultato
id_b | descrizione
---------------------
40 | W
Come funziona
Per ogni riga di B, SQL verifica se esiste almeno una riga in C con lo stesso id_b.
10 >> esiste in C >> escluso
20 >> esiste in C >> escluso
30 >> esiste in C >> escluso
40 >> non esiste >> restituito
caso 2. Con LEFT JOIN ... IS NULL
Spesso si usa IS NULL (fai attenzione: non NOT NULL) per trovare i record non associati.
SELECT b.*
FROM B b
LEFT JOIN C c
ON c.id_b = b.id_b
WHERE c.id_b IS NULL;
Risultato
id_b | descrizione
---------------------
40 | W
Come funziona
La LEFT JOIN mantiene tutte le righe di B:
b.id_b | c.id_b
----------------
10 | 10
20 | 20
30 | 30
40 | NULL
già dal risultato si capisce che fino al id_b 30 hai la lista delle corse assegnate mentre qualle che hanno valore null appartengono alla lista delle disponibilità (o non assegnate)
per la lista delle corse assegnate usi "where c.id_b is not null"
per quelle da assegnare usi "where c.id_b is null"
Filtrando con:
WHERE c.id_b IS NULL
rimangono solo le righe senza corrispondenza.
Differenze tra NOT EXISTS e LEFT JOIN ... IS NULL
NOT EXISTS usa:
WHERE NOT EXISTS (...)
Vantaggi
Semanticamente più chiaro.
Gestisce bene i valori NULL.
Spesso è la soluzione preferita per verificare l'assenza di record correlati.
LEFT JOIN ... IS NULL usa:
LEFT JOIN ...
WHERE c.id_b IS NULL
Vantaggi
Facile da leggere quando si stanno già facendo join.
In molti DBMS il piano di esecuzione è equivalente a NOT EXISTS.
Attenzione a NOT IN
Molti scrivono:
SELECT *
FROM B
WHERE id_b NOT IN (
SELECT id_b
FROM C
);
Se nella sottoquery compare anche un solo NULL, il risultato può essere inatteso e non restituire alcuna riga. Per questo NOT EXISTS è generalmente più sicuro.
In pratica, per cercare i record di B non presenti nella relazione C, la soluzione più robusta è normalmente:
SELECT b.*
FROM B b
WHERE NOT EXISTS (
SELECT 1
FROM C c
WHERE c.id_b = b.id_b
);
la select 1 fa riferimento sempre alla relazione.
la relazione può avere anche delle clausole Where giorno=oggi; where festivo=true; ecc...
alla fine di tutti i filtri avrai sempre e comunque una tabellaA, una relazione C ed una tabellaB
quindi
SELECT b.*
FROM B b //filtrata come meglio credi
WHERE NOT EXISTS (
SELECT 1
FROM C c // filtrata come meglio credi
WHERE c.id_b = b.id_b
);
se usi il caso 2 Con LEFT JOIN ... IS NULL
appena inserisci la relazione (metti i dati nella tabelaC) e riesegui le due query
query relazione presente (servizi assegnati)
SELECT b.*
FROM B b
LEFT JOIN C c
ON c.id_b = b.id_b
WHERE c.id_b IS NOT NULL;
query relazione non presente (servizi da assegnare)
SELECT b.*
FROM B b
LEFT JOIN C c
ON c.id_b = b.id_b
WHERE c.id_b IS NULL;
l'unica cosa da fare per svuotare la lista servizi assegnati è cancellare il record della relazione (tabellaC)
per assegnarlo basta inserire il record della relazione in TabellaC
09/06/2026 - pierpippo ha scritto:
Non deve vuotarsi mica nulla
ho una tabella dalla quale vengono presi dati con varie condizioni una delle quali che essi non siano gia presenti un un'altra tabella:
colpa mia, mi sono espresso male, è la query che si arricchisce o si svuota non i dati memorizzati nelle tabelle.
09/06/2026 - pierpippo ha scritto:
AND NOT EXISTS (SELECT * FROM gbgar_serv_master LEFT JOIN gbgar_serv_detail ON gbgar_serv_master.id_master=gbgar_serv_detail.id_master LEFT JOIN gbgar_corse ON gbgar_serv_detail.id_corsa=gbgar_corse.id_corsa WHERE data='2026-06-06');
non and not exist segui l'esempio. stai relazionando tabellaA con i dati che non esistono nella tabellaC devi fare riferimanto sempre alla relazione
esiste l'ID tabellaA where data=oggi? no, allora mostramelo. il senso è questo stai escludendo i dati già relazionati. usa il caso 2 che sebra molto piu' familiare ad una comune select con join.
non uso i tuoi dati perchè non mi è chiara la gestione dei dati che stai facendo, ma lo do per giusto.