In un sistema di analisi, l'esecuzione di query rappresenta uno dei momenti più importanti in
assoluto. In Hive soprattutto, l'uso di un linguaggio simile a SQL ha permesso di svolgere
elaborazioni in modalità piuttosto semplice senza dover avviare job MapReduce o altre
forme di analisi più complessa. In questa lezione, iniziamo ad osservare la struttura di base
di una query esaminando le direttive per filtrare e limitare i risultati. Per gli
esempi che seguono abbiamo creato, sulla scorta di quanto visto nelle lezioni precedenti,
un database dotato di una tabella che può essere inizializzato (e reinizializzato se già esistente) con il
seguente codice:
DROP DATABASE IF EXISTS banca CASCADE;
CREATE DATABASE banca;
USE banca;
CREATE TABLE transazioni
(data DATE,
importo FLOAT,
codice STRING,
descrizione STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ';';
LOAD DATA LOCAL INPATH 'dati.csv' INTO TABLE transazioni;
Prime query
I dati caricati nella tabella rappresentano transazioni di un conto corrente bancario. Supponiamo di
avere già banca come database corrente, grazie all'impiego di USE
, potremo direttamente
invocare la tabella. Il comando:
SELECT * FROM transazioni;
richiede la lettura dell'intero contenuto della tabella. Ciò, secondo la struttura di
Hive, consisterà nell'accesso a tutti i dati presenti nei file collegati ad essa.
L'output mostrerà i dati recuperati che saranno nel formato seguente:
2018-01-24 1000.0 AS Stipendio gennaio
2018-01-25 -250.0 BA Riscaldamento rata 3
2018-02-01 -300.0 PC Prelievo bancomat 101
...
...
Il comando è perfettamente comprensibile per chiunque abbia già usato il linguaggio
SQL comunque le parti che lo compongono sono:
- il blocco
FROM
introduce il nome della tabella da cui i dati saranno prelevati; SELECT
inizia la direttiva e specifica il nome dei campi della tabella che dovranno
essere restituiti al chiamante. In questo caso il simbolo asterisco (*
) indica che tutti i campi della
tabella dovranno essere restituiti.
Si potrebbe ottenere un numero minore di colonne richiedendo esplicitamente quelle cui
siamo interessati tra il SELECT
e il FROM
:
SELECT data, importo FROM transazioni;
Una query così specificata restituisce un set di risultati in cui appaiono solo due campi, vale
a dire data ed importo dell'operazione:
2018-01-24 1000.0
2018-01-25 -250.0
2018-02-01 -300.0
...
...
La clausola DISTINCT
A volte i risultati di una query possono mostrare delle righe duplicate e ciò può essere un problema
in determinate elaborazioni. Se, ad esempio, volessimo sapere tutti i codici di operazione utilizzati nei
dati a nostra disposizione (intendiamo il terzo campo, popolato da stringhe di due lettere) potremmo svolgere la
seguente interrogazione:
SELECT codice FROM transazioni;
ottenendo righe di questo tipo:
AS
BA
PC
AS
BA
PB
...
...
Si nota subito che già nelle prime righe sono presenti codici uguali (AS e BA per quanto si
vede in questo stralcio). Potremmo richiedere una lista di valori non duplicati usando la
parola chiave DISTINCT
:
SELECT DISTINCT codice FROM transazioni;
e l'intera lista risultante diverrebbe:
AS
BA
BD
PB
PC
VS
Ciò ci permette di vedere subito tutti i codici che appaiono nelle varie righe senza la necessità di operare
raggruppamenti (operazione che analizzeremo bene nelle prossime lezioni).
La clausola WHERE
Con la clausola WHERE
possiamo specificare condizioni di selezione delle singole righe. Lo scopo
di ciò è attuare filtri in maniera da poter scegliere quali righe della tabella possono far parte del set di risultati.
La clausola WHERE
segue il FROM
e deve contenere un'espressione booleana costituita da uno o più confronti (eventualmente
collegati tra loro da opearatori logici) o funzioni che restituiscano valori booleani. Si ricorda a tal proposito che un valore
booleano può essere solo TRUE
(vero) o FALSE
(falso) e rappresenta la veridicità di una determinata espressione.
Esempio:
SELECT * FROM transazioni WHERE importo<0
La query restituisce tutte le righe il cui valore indicato nel campo importo è minore di zero:
2018-01-25 -250.0 BA Riscaldamento rata 3
2018-02-01 -300.0 PC Prelievo bancomat 101
2018-03-25 -250.0 BA Riscaldamento rata 4
...
...
Il simbolo di minore (<
) è l'operatore con cui è stato stabilito il confronto. Gli operatori di confronto
che possono essere utilizzati sono quelli consueti del linguaggio SQL: oltre al minore già citato, abbiamo
il maggiore (>
), minore o uguale (<=
), maggiore o uguale (>=
) e uguale (=
). Per legare più confronti tra loro
è possibile utilizzare i seguenti operatori logici: AND
che restituisce TRUE
solo se entrambi i suoi
operandi sono veri; OR
che per restituire TRUE
richiede che almeno uno dei suoi operandi sia vero; NOT
(indicabile
anche con il punto esclamativo) inverte il valore booleano che lo segue. A questi operatori si può aggiungere IN
utilizzabile
nel formato A IN (valore1, valore2, valore3, ...)
il quale restituisce TRUE
se A equivale a uno dei valori rappresentati
tra parentesi. All'operatore IN
si può applicare la negazione del NOT
pertanto A NOT IN (valore1, valore2, valore3, ...)
sarà
TRUE
se A non equivale a nessuno dei valori indicati tra parentesi.
I seguenti esempi dimostrano l'uso degli operatori di cui abbiamo appena parlato. Questa query restituisce una
selezione delle righe con importo negativo scegliendo solo quelle in cui il codice dell'operazione equivale a BA:
SELECT * FROM transazioni WHERE importo<0 AND codice=='BA'
Questo ciò che otterremo:
2018-01-25 -250.0 BA Riscaldamento rata 3
2018-03-25 -250.0 BA Riscaldamento rata 4
2018-05-11 -520.0 BA Condominio rata 1
Con l'operatore OR
potremo ottenere tutte le righe in cui codice equivarrà a PB o a PC:
SELECT * FROM transazioni WHERE codice='PB' OR codice='PC'
ossia:
2018-02-01 -300.0 PC Prelievo bancomat 101
2018-03-02 -50.0 PB Pagobancomat Ikea
2018-04-11 -300.0 PC Prelievo bancomat 101
2018-05-12 -30.0 PB Pagobancomat Farmacia Rossi
2018-07-10 -500.0 PC Prelievo bancomat 91
Per selezioni di questo tipo può tornare utile anche l'operatore IN
:
SELECT * FROM transazioni WHERE importo<0 AND codice IN ('BA', 'PB')
Avremo in questo caso i seguenti record:
2018-01-25 -250.0 BA Riscaldamento rata 3
2018-03-25 -250.0 BA Riscaldamento rata 4
2018-03-02 -50.0 PB Pagobancomat Ikea
2018-05-11 -520.0 BA Condominio rata 1
2018-05-12 -30.0 PB Pagobancomat Farmacia Rossi
La clausola LIMIT
Allo scopo di ridurre il set di risultati di un'interrogazione si può usare la clausola LIMIT
che determina
quanti record al massimo una query può restituire. Il primo modo di utilizzarla consiste nel concatenarla alla
query indicando il numero di risultati che si desidera:
SELECT * FROM transazioni WHERE importo<0 LIMIT 3
La query cercherà tutte le righe indicanti un importo negativo ma restituirà solo le prime tre:
2018-01-25 -250.0 BA Riscaldamento rata 3
2018-02-01 -300.0 PC Prelievo bancomat 101
2018-03-25 -250.0 BA Riscaldamento rata 4
Si può fare uso di LIMIT
anche in un secondo modo:
SELECT * FROM transazioni WHERE importo<0 LIMIT 2,3
Chiederemo così tre record (il secondo intero passato) ma saltando i primi due risultati (si veda il
primo intero passato) e questo sarà ciò che ci vedremo restituito:
2018-03-25 -250.0 BA Riscaldamento rata 4
2018-03-02 -50.0 PB Pagobancomat Ikea
2018-04-11 -300.0 PC Prelievo bancomat 101