logo logo Dove iniziare Linguaggi Aiuto Blog
Home Dove iniziare Linguaggi Aiuto e Supporto Biadets Blog

Leggere i dati in MySQL

Dopo aver creato le tabelle e inserito i dati, il passo successivo è recuperare i dati dal database. In MySQL è possibile farlo usando l'istruzione SELECT, che ci permette di leggere righe e colonne dalle tabelle.

Con Node.js possiamo eseguire query SELECT per ottenere i dati e utilizzarli nella nostra applicazione, come mostrare un elenco di prodotti, visualizzare profili utente o generare report di dati.

La query SELECT di base

L'istruzione SELECT è il comando più utilizzato in MySQL. Serve per estrarre dati da una o più tabelle del database. La sintassi base prevede di specificare quali colonne vogliamo leggere e da quale tabella.

Per selezionare tutti i dati da una tabella, utilizziamo SELECT * FROM seguito dal nome della tabella. L'asterisco * significa "tutte le colonne".

const mysql = require("mysql");
const con = mysql.createConnection({
  host: "localhost",
  user: "root",
  password: "la_tua_password",
  database: "esempio"
});

con.connect(function (err) {
  if (err) throw err;

  const sql = "SELECT * FROM utenti";
  
  con.query(sql, function (err, result) {
    if (err) throw err;
    console.log(result);
  });
});

Il parametro result nella funzione di callback in con.query contiene un array di oggetti JavaScript. Ogni oggetto rappresenta una riga della tabella, e le proprietà dell'oggetto corrispondono alle colonne. Se la tabella utenti ha colonne id, nome ed email, otterremo qualcosa come:

[
  { id: 1, nome: 'Mario', email: '[email protected]' },
  { id: 2, nome: 'Luigi', email: '[email protected]' },
  { id: 3, nome: 'Giacomo', email: '[email protected]' }
]

Selezionare colonne specifiche

Nella pratica, raramente abbiamo bisogno di tutte le colonne. Selezionare solo le colonne necessarie migliora le prestazioni del database e riduce il traffico di rete, soprattutto quando le tabelle contengono molte colonne o dati di grandi dimensioni.

const sql = "SELECT nome, email FROM utenti";

con.query(sql, function (err, result) {
  if (err) throw err;
  console.log(result);
});

In questo caso, l'array conterrà solo le proprietà specificate dopo SELECT:

[
  { nome: 'Mario', email: '[email protected]' },
  { nome: 'Luigi', email: '[email protected]' },
  { nome: 'Giacomo', email: '[email protected]' }
]

Rinominare le colonne

Quando eseguiamo una query, i nomi delle colonne restituite corrispondono a quelli definiti nella tabella. Tuttavia, a volte può essere utile rinominare temporaneamente queste colonne nel risultato della query, ad esempio per renderle più leggibili, più coerenti con il codice o per evitare conflitti di nomi. 

Per farlo, in MySQL utilizziamo la parola chiave AS, seguita dal nuovo nome che vogliamo dare alla colonna nel risultato.

Il nuovo nome è solo una "rinomina temporanea", non modifica la struttura della tabella nel database: vale solo per quella query.

const sql = "SELECT nome AS nome_utente, email AS indirizzo_email FROM utenti";

con.query(sql, function (err, result) {
  if (err) throw err;
  console.log(result[0].nome_utente); // Invece di result[0].nome
});

La clausola WHERE

La clausola WHERE è fondamentale per filtrare i risultati. Senza di essa, verrebbero restituite tutte le righe della tabella, un’operazione potenzialmente pesante se contiene migliaia o milioni di dati.

Con WHERE specifichiamo una o più condizioni che le righe devono soddisfare per essere incluse nei risultati.

Ad esempio, selezioniamo soltanto l'utente che si chiama Mario:

const sql = "SELECT * FROM utenti WHERE nome = 'Mario'";

con.query(sql, function (err, result) {
  if (err) throw err;
  console.log(result);
});

Operatori di confronto

MySQL supporta numerosi operatori per confrontare valori nelle condizioni:

// Uguale: trova utenti con id esattamente uguale a 5
const sql1 = "SELECT * FROM utenti WHERE id = 5";

// Diverso: trova tutti tranne Mario
const sql2 = "SELECT * FROM utenti WHERE nome != 'Mario'";
// Alternativa con <>
const sql3 = "SELECT * FROM utenti WHERE nome <> 'Mario'";

// Maggiore di: utenti con id superiore a 10
const sql4 = "SELECT * FROM utenti WHERE id > 10";

// Minore o uguale: utenti con id fino a 20
const sql5 = "SELECT * FROM utenti WHERE id <= 20";

L'operatore LIKE

LIKE è particolarmente utile per cercare pattern di testo. Ad esempio, possiamo ricercare un testo che abbia una parte di stringa specificata. L'operatore LIKE utilizza due caratteri speciali:

  • % rappresenta zero o più caratteri qualsiasi.
  • _ rappresenta esattamente un carattere qualsiasi.

// Nomi che iniziano con "M"
const sql1 = "SELECT * FROM utenti WHERE nome LIKE 'M%'";

// Email che finiscono con @gmail.com
const sql2 = "SELECT * FROM utenti WHERE email LIKE '%@gmail.com'";

// Nomi che contengono "ar" in qualsiasi posizione
const sql3 = "SELECT * FROM utenti WHERE nome LIKE '%ar%'";

// Nomi di esattamente 5 caratteri che iniziano con M
const sql4 = "SELECT * FROM utenti WHERE nome LIKE 'M____'";

Nell'esempio, quando utilizziamo M% andiamo a cercare tutti gli utenti che hanno nome che inizia per M. Con %ar%, invece, otteniamo i nomi che contengono all'interno ar, come Marco.

L'operatore IN

Invece di scrivere una sequenza di diverse condizioni OR, possiamo usare l'operatore IN per verificare se un valore appartiene a una lista:

// Questi due sono equivalenti
const sql1 = "SELECT * FROM utenti WHERE id = 1 OR id = 3 OR id = 5";
const sql2 = "SELECT * FROM utenti WHERE id IN (1, 3, 5)";

// Funziona anche con stringhe
const sql3 = "SELECT * FROM utenti WHERE nome IN ('Mario', 'Luigi', 'Giovanni')";

Nell'esempio, con id IN (1,3,5) verranno restituiti tutti gli utenti che hanno id uguale a 1, 3, o 5, mentre con nome IN ('Mario','Luigi','Giovanni') quelli con un nome all'interno della lista.

L'operatore BETWEEN

Per verificare se un valore rientra in un intervallo, si può utilizzare l'operatore BETWEEN. L'intervallo è da specificare con AND. In questo modo, risulta più leggibile rispetto a >= e <=:

// Questi due sono equivalenti
const sql1 = "SELECT * FROM utenti WHERE id >= 10 AND id <= 20";
const sql2 = "SELECT * FROM utenti WHERE id BETWEEN 10 AND 20";

// Funziona anche con date
const sql3 = "SELECT * FROM ordini WHERE data_ordine BETWEEN '2024-01-01' AND '2024-12-31'";

Valori NULL

Per verificare se una colonna ha valore NULL (cioè non contiene nessun valore), dobbiamo usare IS NULL. Nel caso in cui si voglia verificare che contenga qualcosa, possiamo usare IS NOT NULL. Non si possono usare, invece, gli operatori di uguaglianza (=):

// Trova utenti senza email
const sql1 = "SELECT * FROM utenti WHERE email IS NULL";

// Trova utenti con email
const sql2 = "SELECT * FROM utenti WHERE email IS NOT NULL";

Combinare condizioni con AND e OR

Spesso abbiamo bisogno di condizioni più complesse. Possiamo combinare più condizioni usando gli operatori logici AND e OR.

Con AND, tutte le condizioni devono essere vere perché la riga sia inclusa:

// Utenti che si chiamano Mario e hanno un'email gmail
const sql = "SELECT * FROM utenti WHERE nome = 'Mario' AND email LIKE '%@gmail.com'";

Con OR, è sufficiente che almeno una condizione sia vera:

// Utenti che si chiamano Mario o Luigi
const sql = "SELECT * FROM utenti WHERE nome = 'Mario' OR nome = 'Luigi'";

Possiamo anche combinare AND e OR usando le parentesi per controllare l'ordine di valutazione:

const sql = "SELECT * FROM prodotti WHERE (categoria = 'elettronica' AND prezzo < 50) OR (categoria = 'libri' AND prezzo > 100)";

Senza parentesi, MySQL valuta prima gli AND e poi gli OR, che potrebbe non essere quello che vogliamo.

Usare parametri nelle query

Uno degli errori più pericolosi nella programmazione con i database è la SQL injection, un attacco dove un utente malintenzionato inserisce codice SQL dannoso nei campi di input.

Abbiamo approfondito il problema dell'SQL injection nella lezione sull'inserimento di dati nelle tabelle.

Quando riceviamo un input dall'utente, la soluzione principale per evitare vulnerabilità è usare parametri preparati, indicati con ?:

const nome = "Mario"; // Valore che può provenire dall'utente
const sql = "SELECT * FROM utenti WHERE nome = ?";

con.query(sql, [nome], function (err, result) {
  if (err) throw err;
  console.log(result);
});

MySQL gestisce automaticamente la sicurezza delle stringhe ed evita eventuali SQL injection. Il valore nell'array sostituisce il punto interrogativo nell'ordine in cui appaiono.

Per più parametri, basta aggiungere più punti interrogativi e più valori nell'array:

const nome = "Mario";
const email = "[email protected]";
const sql = "SELECT * FROM utenti WHERE nome = ? AND email = ?";

con.query(sql, [nome, email], function (err, result) {
  if (err) throw err;
  console.log(result);
});

Prova!Completa gli spazi vuoti con il testo appropriato.
// Seleziona tutti i dati dalla tabella utenti
const sql = " * utenti";

Prova!Scegli l'opzione corretta tra quelle elencate.
// Come filtri i risultati per ottenere solo gli utenti con nome "Mario"?
SELECT * FROM utenti ____ nome = 'Mario';