[MYSQL] Query su tabelle con clausola "essenziale"

perseoclub

Utente Attivo
28 Nov 2015
91
0
6
Ho avuto difficoltà anche a scrivere il titolo del post.. o_O

In pratica ho 3 tabelle in relazione tra loro..

`tab1` (rel 1→N) `tab2` (rel 1→N) `tab3`

e vorrei come risultato (distinto) tutti i `tb1_campo` dove ogni `tb2_id` ha almeno un campo `tb3_id` ad esso associato.

Scenario:


`tab1`
Codice:
+--------+-----------+
| tb1_id | tb1_campo |
+--------+-----------+
|   1    |    uno    |
+--------+-----------+


`tab2`
Codice:
+--------+------------+-----------+
| tb2_id | tb2_tb1_id | tb2_campo |
+--------+------------+-----------+
|   1    |     1      |    one    |
|   2    |     1      |    two    |
|   3    |     1      |    tree   |
+--------+------------+-----------+


`tab3` → 1° CASO (RITORNA 'uno')
Codice:
+--------+------------+-----------+
| tb3_id | tb3_tb2_id | tb3_campo |
+--------+------------+-----------+
|   1    |     1      |    true   |
|   2    |     1      |    true   |
|   3    |     2      |    true   |
|   4    |     2      |    true   |
|   5    |     3      |    true   |
+--------+------------+-----------+


`tab3` → 2° CASO (NESSUN RISULTATO)
Codice:
+--------+------------+-----------+
| tb3_id | tb3_tb2_id | tb3_campo |
+--------+------------+-----------+
|   1    |     1      |    true   |
|   2    |     1      |    true   |
|   3    |     2      |    true   |
|   4    |     2      |    true   |
+--------+------------+-----------+
 
Ultima modifica:
Questa pare funzionare.. ma essendo andato un po' a tentativi, mi potete confermate che sia il modo migliore?

SELECT DISTINCT
tab1.tb1_campo
FROM
tab1, tab2, tab3, (SELECT DISTINCT tb1_id FROM tab1, ( SELECT tb2_id FROM tab2 WHERE NOT EXISTS (SELECT tb3_id FROM tab3 WHERE tb2_id = tb3_id) ) as tmp WHERE tb1_id = tb2_id ) as escludi
WHERE
tab1.tb1_id = tb2_id AND
tb3_id = tb2_id AND
tab1.tb1_id != escludi.tb1_id
 
[EDIT] Query migliorata!

SELECT DISTINCT
tab1.tb1_campo
FROM
tab1, tab2, tab3
WHERE
tab1.tb1_id = tb2_id AND
tb3_id = tb2_id AND
tab1.tb1_id NOT IN (SELECT DISTINCT tb1_id FROM tab1, ( SELECT tb2_id FROM tab2 WHERE NOT EXISTS (SELECT tb3_id FROM tab3 WHERE tb2_id = tb3_id) ) as tmp WHERE tb1_id = tb2_id )
 
permettimi una osservazione, nella query migliorata
PHP:
tab1, tab2, tab3
 WHERE
 tab1.tb1_id = tb2_id AND
forse dovrebbe essere
PHP:
tab1, tab2, tab3
 WHERE
 tab1.tb1_id = tab2.tb1_id AND
e di conseguenza tutte le altre,
ma forse non ho capito nulla .....
 
Ultima modifica:
Certo Martino! Nel trasporre il mio codice a questo modello strutturale ho dimenticato il suffisso della tabella Tab2. (Nel codice quel campo è tb2_tb1_id.. quindi non ha ambiguità.. e non mi era servito specificare il nome della tabella..)

Sent from my Redmi 3 using Tapatalk
 
secondo me il problema risiede nel nome delle colonne che usi per legare le tabelle,
per il suffisso non avrei scritto

come indici delle tabelle prova ad usare le serie 100.... (tab1) , 200..... (tab2) e 300.... (tab3)
perché usando sempre progressivi che partono da 1 è facile confondere le cose

questo è il risultato della tua query, usando le sequenze che ti ho indicato,
(credo di aver ben sistemato i nomi delle tabelle)
Cattura.PNG

ho poi usato una "banalissima" query
Cattura.PNG

la tua query così modificata,
Cattura.PNG
 
Ultima modifica:
Marino,

non riesco a cogliere il tuo suggerimento..

La query funziona perfettamente (almeno così pare, finché non rileverò dei bug), ma volevo capire se potrebbe essere scritta in maniera migliore, non nella sintassi, ma nella logica, cioè se esiste una strada più sicura e professionale..

Per quanto riguarda la sintassi del mio database ho optato per questa nomenclatura:

TABELLE abbreviate a 3 lettere per evitare di fare scrivere tanti nomi lungi.. e suffissi dei CAMPI (univoci per ogni tabella del db) da 2 lettere..

Quindi ad esempio:

La tabella clienti diventa `cli` → e ogni campo ha un suffisso di 2 lettere `cl_` → quindi `cl_id`, `cl_codide`, `cl_nome`, ecc...

La tabella prodotti diventa `pro` → `pr_id`, `pr_prodotto`, `pr_prezzo`, ecc...

La tabella ordini diventa `ord` → `or_id`, `or_cl_id`, `or_pr_id`, `or_data`, `or_eseguito`, ecc...

Nel caso di tabelle simili: prenotazioni e prestazioni.. diventano `prn.pn_id` e `prs.ps_id`

In questo modo non ho mai ambiguità nelle query.. (almeno credo)

Nonostante questo nelle query continuo ad inserire anche il prefisso della tabella..
Codice:
SELECT ord.or_data FROM ord, cli WHERE cli.cl_id = ord.or_cl_id AND cli.cl_nome = ?


anche se MYSQL leggerebbe la forma più snella (senza la dichiarazione delle tabelle):
Codice:
SELECT or_data FROM ord, cli WHERE cl_id = or_cl_id AND cl_nome = ?

Mi trovo abbastanza bene con questa nomenclatura e ho optato per il suffisso a 2 lettere anziché identico al nome della tabella proprio per non confondermi durante la scrittura del codice.. e per cogliere immediatamente al volo che a 2 è un campo.. a 3 la tabella.. Alla lunga forse avevi ragione tu, avrei potuto optare per il suffisso uguale al nome della tabella. Infatti avendo una trentina di tabelle.. tra i suffissi a 2 e i nomi a 3 delle tabelle sto un po' impazzendo.. ma sono molto concentrato.. :
 
La query funziona perfettamente (almeno così pare, finché non rileverò dei bug),
l'esempio che hai postato, credo non funzioni bene, ho fatto delle prove ed ho visto che non estrae ciò che ritenevi dovesse estrarre

probabilmente l'esempio non corrisponde alla query che hai usato realmente

se la query che usi funziona, dimentica tutto quello che ho scritto
inutile ragionare su qualcosa che non è applicato
 
Era come l'avevo trasposta.. Ho corretto i nomi dei campi delle tabelle in cima al post e riadattato il codice della query.. Prova così?
Codice:
SELECT DISTINCT
    tb1_campo
FROM
    tab1, tab2, tab3
WHERE
    tb1_id NOT IN (
        SELECT DISTINCT
            tb2_tb1_id
        FROM tab2 WHERE NOT EXISTS (
            SELECT
                tb3_id
            FROM tab3 WHERE tb3_tb2_id = tb2_id
        )
    )
 
Ultima modifica:
PHP:
SELECT DISTINCT tb1_campo
FROM tab1, tab2, tab3
se estrai solo un campo da una tabella, perché elenchi 3 tabelle ?

PHP:
FROM tab3 WHERE tb3_tb2_id = tb2_id
tb2_id non è presente in nessuna select, di conseguenza la query estrae tutta la tabella tab1

nel primo post hai scritto
vorrei come risultato (distinto) tutti i `tb1_campo` dove ogni `tb2_id` ha almeno un campo `tb3_id` ad esso associato
"NOT IN" e "NOT EXIST" mi sembrano una negazione ......
 
Ultima modifica:
il DISTINCT l'ho lasciato perché senza mi ripete 'uno' tante volte quanti sono i record analizzati.. A me serve una volta sola.

Mi sa che ho esposto male il problema.. a me servono:

quei valori distinti di 'tab1', dove ogni riga di 'tab2' ad esso associato, abbia a sua volta almeno una riga di 'tab3' associata.

Facendo un esempio con i paragrafi di un libro:
__(tab1)__________(tab2)______________(tab3)
Sezione 1 → Capitolo 1.1, 1.2 → Paragrafo 1.1.1, 1.1.2, 1.1.3, 1.2.1
Sezione 2 → Capitolo 2.1, 2.2, 2.3 → Paragrafo 2.1.1, 2.1.2, 2.2.1 (manca il paragrafo 2.3.x)

Quindi la query mi restituisce solo la Sezione 1... perché nella Sezione 2 il capitolo 2.3 non ha un paragrafo..

Spero di essermi spiegato meglio :)

Io ho ragionato così.. prendi tutti i valori di tab2 (correlati a tab1) dove non esiste (NOT EXISTS) la correlazione con tab3.. e sottraili (NOT IN) all'insieme totale..
Ma avrei potuto anche scrivere direttamente WHERE EXISTS.. la correlazione.. ma essendo andato a tentativi e mi funzionava ho avuto paura di fare dei casini.. e ho chiesto consiglio.

Ripensandoci, a me non serve almeno una correlazione, ma: se esiste almeno una non-correlazione.. non selezionare.. (che sembrerebbe una negazione)
 
Ultima modifica:

Discussioni simili