Operatore UNION

Gli argomenti di questa pagina

  • Introduzione
  • Definizione della clausola UNION
  • La sintassi per la clausola UNION
  • Le tabelle in esame
  • I files SQL necessari per creare le tabelle
  • Qualche semplice esempio
  • Prima soluzione
  • Seconda soluzione
  • Estrazione dati da una normale tabella e da due tabelle relazionate
  • Usare la clausola WHERE alle Query SELECT

Introduzione

La clausola UNION viene usata quando, da due tabelle, non necessariamente relazionate tra loro, vogliamo estrarre dei record che contengono gli stessi tipi di campi. Esempio:
l'anagrafica dei fornitori e degli impiegati
l'anagrafica degli operai e degli impiegati
l'anagrafica degli studenti e degli insegnanti.

Definizione della clausola UNION

La clausola UNION, come indica il suo nome, 'unisce due o puù Query SELECT' per restituire un unico Resultset. Per farla funzionare correttamente e senza sollevare errori è tuttavia necessario applicare alcune regole fondamentali:

  • Le due Query SELECT estraggono lo stesso numero di campi
  • I campi delle due Query debbono essere dello stesso tipo: un tipo 'date' di un campo della prima Query deve corrispondere al tipo 'date' del corrispettivo campo della seconda Query; un tipo 'testo' di un campo della prima Query corrisponde al tipo 'testo' del corrispettivo campo della seconda Query e così via.

Per i tipi compatibili ma non necessariamente uguali, esegue automaticamente la più ovvia conversione. Per esempio per due campi numerici di cui uno è decimale e l'altro è intero, esegue la conversione al tipo più ovvio.

La sintassi per la clausola UNION

SELECT col_a, col_b, col_c FROM table_1
UNION
SELECT col_1, col_2, col_3 FROM table_2

Ciascuna delle Query SELECT può essere scritta in una delle forme viste finora nei vari capitoli purchè restituiscano le giuste colonne nel giusto posto.

I nomi dei campi della seconda Query SELECT vengono sovrascritti dai nomi dei campi della prima Query SELECT. Ciò significa che se nella prima Query SELECT abbiamo un campo 'nominativo' e nella seconda Query SELECT abbiamo nella corrispondente posizione un campo 'nome', tutta la colonna relativa a quei campi sarà denominata 'nominativo'.

Per impostazione predefinita, la clausola UNION elimina le righe duplicate dal resultset, anche se non si usa esplicitamente l'operatore DISTINCT. Perciò è detto che la clausola UNION è la scorciatoia di UNION DISTINCT.
Se si desidera ottenere anche righe duplicate, è possibile utilizzare la clausola UNION ALL esplicitamente.

Le tabelle in esame

I nostri studi li eseguiremo su queste tabelle:

Per la tabella sql_rubrica
Field Type Null Key Default Extra
id int NO PRI auto_increment
codice varchar(50) NO
cognome varchar(250) NO
nome varchar(250) NO
indirizzo varchar(250) NO
cap varchar(250) NO
citta varchar(250) NO
prov varchar(10) NO
data_nascita date NO
telefono varchar(250) NO
I campi della tabella sql_rubrica:
id, codice, cognome, nome, indirizzo, cap, citta, prov, data_nascita, telefono
Per la tabella sql_agenda
Field Type Null Key Default Extra
id int NO PRI auto_increment
cognome varchar(250) NO
nome varchar(250) NO
indirizzo varchar(250) NO
id_citta int NO
data_nascita date NO
telefono varchar(250) NO
I campi della tabella sql_agenda:
id, cognome, nome, indirizzo, id_citta, data_nascita, telefono
Per la tabella sql_mag_fornitori
Field Type Null Key Default Extra
id_fornitore int NO PRI auto_increment
rag_sociale varchar(150) NO
indirizzo varchar(200) NO
telefono varchar(50) NO
I campi della tabella sql_mag_fornitori:
id_fornitore, rag_sociale, indirizzo, telefono
Per la tabella sql_citta
Field Type Null Key Default Extra
id int NO PRI auto_increment
cap varchar(10) YES
citta varchar(250) YES
prov varchar(10) YES
I campi della tabella sql_citta:
id, cap, citta, prov

I files SQL necessari per creare le tabelle

I files SQL necessari a creare queste tabelle sono state mostrate nella pagina iniziale di questo settore.

Qualche semplice esempio

Ora vediamo alcuni semplici esempi.
Nel capitolo precedente abbiamo visto come usare le LEFT JOIN e RIGHT JOIN. Riporto una sintesi della definizione delle due JOIN:

  • LEFT JOIN: riporta tutte le righe della tabella "di sinistra" e le corrispondenti righe della tabella "di destra", riempiendo con NULL i campi che, nella riga estratta, non hanno corrispondenze
  • RIGHT JOIN: è l'opposto della LEFT e riporta tutte le righe della tabella "di destra" e le corrispondenti righe della tabella di "sinistra", con NULL i campi che, nella riga estratta, non hanno corrispondenze

Vediamo di porre un quesito al nostro DB.

Mostra il cognome, nome e indirizzo dei contatti della tabella rubrica e quelli della tabella agenda

Prima soluzione

Per ottenere tutte le righe di entrambe le tabelle occorrerebbe una LEFT JOIN e una RIGHT JOIN.
La prima cosa che ci verrebbe in mente sarebbe quella di usare la clausola UNION su due Query SELECT, una che usa la JOIN LEFT e l'altra che usa la JOIN RIGHT come mostrato nell'esempio qui in basso.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
$Query 
"
SELECT 
sql_rubrica.cognome AS rub_cognome, 
sql_rubrica.nome AS rub_nome, 
sql_rubrica.indirizzo AS rub_indirizzo, 
sql_agenda.cognome AS ag_cognome, 
sql_agenda.nome AS ag_nome, 
sql_agenda.indirizzo AS ag_indirizzo
FROM sql_rubrica LEFT JOIN sql_agenda 
ON sql_rubrica.id = sql_agenda.id
UNION 
SELECT 
sql_rubrica.cognome AS rub_cognome, 
sql_rubrica.nome AS rub_nome, 
sql_rubrica.indirizzo AS rub_indirizzo, 
sql_agenda.cognome AS ag_cognome, 
sql_agenda.nome AS ag_nome, 
sql_agenda.indirizzo AS ag_indirizzo
FROM sql_rubrica RIGHT JOIN sql_agenda 
ON sql_rubrica.id = sql_agenda.id
"
;
?>
103 record trovati
20 record visualizzati
rub_cognome rub_nome rub_indirizzo ag_cognome ag_nome ag_indirizzo
Forlini Andrea VIA DEI GERANI Forlini Andrea VIA DEI GERANI
Pioggia Ernesto VIA GRAMSCI 14 A Pioggia Ernesto VIA GRAMSCI 14 A
Armonia Laura VIA CAVOUR Armonia Laura VIA CAVOUR
Caldarone Innocenzo VIA SABIN 34/2 Caldarone Innocenzo VIA SABIN 34/2
Zarbo Veriano VIA DEL TUSCOLANO 1 Zarbo Veriano VIA DEL TUSCOLANO 1
D'Agate Federica VIA BREDINA 6 D'Agate Federica VIA BREDINA 6
Clotilde Marinella VIA.GIUSEPPE DI VITTORIO, 41 Clotilde Marinella VIA.GIUSEPPE DI VITTORIO, 41
Biancarosa Francesca VIA PO, 31 Biancarosa Francesca VIA PO, 31
Burranca Cristian VIA BRIGONI, 6 Burranca Cristian VIA BRIGONI, 6
Said Antomio VIA DEI GERANI Said Antomio VIA DEI GERANI
Querio Angela VIA DEL TUSCOLANO 1 Querio Angela VIA DEL TUSCOLANO 1
Baldoni Serena VIA DELLA CHIMICA N.9 Baldoni Serena VIA DELLA CHIMICA N.9
Serrone Diamora VIA CAVOUR Serrone Diamora VIA CAVOUR
Caldiero Giuseppina VIA MATTEO RICCI, 12 Caldiero Giuseppina VIA MATTEO RICCI, 12
Lomo Dalia VIA SABIN, 34/2 Lomo Dalia VIA SABIN, 34/2
Zuna Clotilde VIA SABIN, 34/2 Zuna Clotilde VIA SABIN, 34/2
D'Alessandro Micdas Via dei Sibillini D'Alessandro Micdas Via dei Sibillini
Oristano Gaby Bo Via Manzoni Oristano Gaby Bo Via Manzoni
NULL NULL NULL giulio cesare
NULL NULL NULL pinco pallino
... ... ... ... ... ...

Tuttavia il risultato non è molto soddisfaciente, almeno in questo caso. I contatti della prima tabella vengono mostrati a fianco di quelli della seconda tabella e, se le due tabella non hanno record in egual numero, i record mancanti della tabella più piccola vengono segnalati come NULL, come mostrato nell'output mostrato qui sopra dove vengono mostrati solo gli ultimi record.

Seconda soluzione

La soluzione a questi problemi è più semplice di quel che si possa pensare. Infatti basta usare la clausola UNION su due semplici Query: la prima su una tabella, la seconda sulla seconda tabella.
L'unica accortezza da usare è quella di rispettare le regole della clausola UNION:
stesso numero e stesso ordine dei campi usati per le due Query SELECT. Se il numero dei campi non è uguale nelle due Query SELECT si incorre nell'errore:
The used SELECT statements have a different number of columns.

1
2
3
4
5
6
7
8
9
<?php
$Query 
"
(SELECT id, cognome, nome , indirizzo 
FROM sql_rubrica)
UNION 
(SELECT id, cognome, nome, indirizzo 
FROM sql_agenda)
"
;
?>
103 record trovati
20 record visualizzati
id cognome nome indirizzo
1 Migliavacca Luigi VIA P. FIMIANI TRIVIO
2 Rizzi Carlo VIA SABIN, 34/2
3 Liberali Franca VIA DEL TUSCOLANO, 1
4 Di Maggio Mario TERMINAL CONTENITORI MOLO VII
5 Scicchitano Andrea VIA SABIN, 34/2
6 Edelvisi Maurizio VIA MATTEO RICCI, 12
7 Gerardini Silvano Z.I SAMBUCETO
8 Pasotti Alessio VIA SABIN, 34/2
9 Calvi Giovanni VIA SABIN, 34/2
10 Poggi Giuseppe VIA SABIN, 34/2
11 Curti Oreste STRADA MARCHESANE, 43_4
12 Borsotti Mirella VIA DEL TUSCOLANO, 1
13 Franchinotti Anna VIA BREDINA, 6
14 Pischedda Giovanni VIA MATTEO RICCI, 12
15 Maini Marilena MACRON TICHON STREET, 27
16 Boscati Andrea VIA MATTEO RICCI, 12
17 Bazzotti Pietro VIA SABIN, 34/2
18 Scicchitano Pierluigi STRADA MARCHESANE, 434
19 Dionisio Andrea VIA DEL TUSCOLANO, 1
20 Traina Giovanni VIA SABIN, 34/2
... ... ... ...

Estrazione dati da una normale tabella e da due tabelle relazionate

Poniamo il quesito al nostro DB in altro modo.

Mostra il nominativo completo, città e indirizzo dei contatti della tabella rubrica e quelli della tabella agenda

Qui entra in ballo una terza tabella per reperire anche il nome della città dei nominativi registrati nella tabella sql_agenda (seconda Query SELECT).
Nella Query visibile qui di seguito possiamo notare alcune note fatte più sopra.

Le due Query SELECT usate per la Query UNION non sono perfettamente uguali, ma semplicemente simili:

  • la prima Query richiama i campi della sola tabella sql_rubrica
  • la seconda Query richiama i campi da due tabelle:
    • sql_agenda che al posto del nome della città ha un id_citta che fa riferimento ad una specifica città di un'altra tabella
    • sql_citta memorizza tutte le città con relativo CAP e PROV

Il numero ed il tipo di campi delle due Query SELECT debbono corrispondere:

  • nella prima Query SELECT abbiamo unito i due campi 'cognome' e 'nome'
  • nella seconda Query SELECT non si può lasciare separati i due campi, ma è necessario che siano uniti anche in questa.

I nomi dei campi della prima Query SELECT sovrascrivono i corrispondenti nomi della seconda Query SELECT. Questa cosa è visibile nella riga delle intestazioni di colonna della tabella che ospita il resultset.

  • Il campo chiamato 'nome_completo' della seconda Query SELECT viene sovrascritto dal campo chiamato 'nominativo' della prima Query SELECT
  • Il campo chiamato 'tabella' della seconda Query SELECT viene sovrascritto dal campo chiamato 'tab' della prima Query SELECT

Nell'esempio che segue per motivi di spazio il resultset mostra solo alcune righe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$Query 
"
SELECT 
CONCAT_WS( ' ', cognome, nome ) AS nominativo, 
citta, 
indirizzo
FROM sql_rubrica
UNION
SELECT 
CONCAT_WS( ' ', sql_agenda.cognome, sql_agenda.nome ) AS nome_completo, 
sql_citta.citta, 
sql_agenda.indirizzo
FROM sql_agenda INNER JOIN sql_citta 
ON sql_agenda.id_citta = sql_citta.id
"
;
?>
124 record trovati
20 record visualizzati
nominativo citta indirizzo
Migliavacca Luigi Varena VIA P. FIMIANI TRIVIO
Rizzi Carlo Varena VIA SABIN, 34/2
Liberali Franca Abbadia Lariana VIA DEL TUSCOLANO, 1
Di Maggio Mario Ville di Fano TERMINAL CONTENITORI MOLO VII
Scicchitano Andrea Ville di Fano VIA SABIN, 34/2
Edelvisi Maurizio Ville di Fano VIA MATTEO RICCI, 12
Gerardini Silvano Ville di Fano Z.I SAMBUCETO
Pasotti Alessio Correzzana VIA SABIN, 34/2
Calvi Giovanni Marsiliana VIA SABIN, 34/2
Poggi Giuseppe Abbadia Lariana VIA SABIN, 34/2
Curti Oreste Ville di Fano STRADA MARCHESANE, 43_4
Borsotti Mirella Ville di Fano VIA DEL TUSCOLANO, 1
Franchinotti Anna Abbadia Lariana VIA BREDINA, 6
Pischedda Giovanni Falconara Alta VIA MATTEO RICCI, 12
Maini Marilena Borgo S. Dalmazzo MACRON TICHON STREET, 27
Boscati Andrea Ville di Fano VIA MATTEO RICCI, 12
Bazzotti Pietro Abbadia Lariana VIA SABIN, 34/2
Scicchitano Pierluigi Abbadia Lariana STRADA MARCHESANE, 434
Dionisio Andrea San Leonardo in Passiria VIA DEL TUSCOLANO, 1
Traina Giovanni Ville di Fano VIA SABIN, 34/2
... ... ...

Usare la clausola WHERE alle Query SELECT

Ora proviamo a mettere un filtro ad una a ad entrambe le Query SELECT unite con la clausola UNION.

Mostra i contatti registrati nella rubrica e che abitano in una determinata città ed i contatti registrati nell'agenda e che abitano in una determinata città

Il resultset risultante è ora filtrato ed è visualizzato in maniera integrale.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
$Query 
"
(SELECT id, 
cognome, 
nome, 
citta,
prov
FROM sql_rubrica
WHERE citta = 'Agropoli')

UNION 

(SELECT sql_agenda.id, 
sql_agenda.cognome, 
sql_agenda.nome, 
sql_citta.citta,
sql_citta.prov
FROM sql_agenda INNER JOIN sql_citta 
ON sql_agenda.id_citta = sql_citta.id
WHERE sql_citta.citta = 'Agropoli')
"
;
?>
21 record letti
id cognome nome citta prov
88 Zarbo Veriano Agropoli DE
89 D'Agate Federica Agropoli DE
90 Clotilde Marinella Agropoli DE
91 Biancarosa Francesca Agropoli DE
92 Burranca Cristian Agropoli DE
93 Said Antomio Agropoli GH
94 Querio Angela Agropoli GH
95 Baldoni Serena Agropoli GH
96 Serrone Diamora Agropoli DE
97 Caldiero Giuseppina Agropoli DE
98 Lomo Dalia Agropoli DE
99 Zuna Clotilde Agropoli DE
88 Zarbo Veriano Agropoli GH
89 D'Agate Federica Agropoli GH
90 Clotilde Marinella Agropoli GH
91 Biancarosa Francesca Agropoli GH
92 Burranca Cristian Agropoli GH
96 Serrone Diamora Agropoli GH
97 Caldiero Giuseppina Agropoli GH
98 Lomo Dalia Agropoli GH
99 Zuna Clotilde Agropoli GH

 

 



settore tecnico il sito di lorettabweb il Forum di sostegno
il forum il forum il forum