Context engineering
Comprendere e utilizzare le istruzioni fondamentali DML: INSERT, UPDATE, DELETE.
Imparare le buone pratiche: transazioni, prepared statements, controllo integrità, prevenzione SQL injection.
Realizzare una tabella clienti e popolarla con esempi pratici.
Prima di modificare dati in un database è importante conoscere le proprietà ACID:
Atomicità: tutte le operazioni di una transazione avvengono tutte o nessuna.
Consistenza: la transazione porta il DB da uno stato consistente a un altro.
Isolamento: transazioni concorrenti non si interferiscono.
Durabilità: una volta confermata, la transazione è persistente.
Usare BEGIN / COMMIT / ROLLBACK per raggruppare operazioni e poter annullare in caso di errore.
Esempio (PostgreSQL / MySQL-ish):
BEGIN;
-- serie di operazioni INSERT/UPDATE/DELETE
COMMIT;
-- o in caso di errore
ROLLBACK;
INSERT INTO table_name (col1, col2, col3)
VALUES (val1, val2, val3);
INSERT INTO customers (first_name, last_name, email, city)
VALUES ('Luca', 'Bianchi', 'luca.bianchi@example.com', 'Firenze');
INSERT INTO customers (first_name, last_name, email, city)
VALUES
('Anna', 'Rossi', 'anna.rossi@example.com', 'Milano'),
('Marco', 'Verdi', 'marco.verdi@example.com', 'Torino'),
('Giulia', 'Neri', 'giulia.neri@example.com', 'Bologna');
INSERT INTO customers_backup (first_name, last_name, email, city)
SELECT first_name, last_name, email, city FROM customers
WHERE created_at < '2023-01-01';
Per ottenere l'id generato:
INSERT INTO customers (first_name, last_name, email)
VALUES ('Paolo', 'Rossi', 'paolo.rossi@example.com')
RETURNING id;
UPDATE table_name
SET col1 = new_val1, col2 = new_val2
WHERE condition;
Attenzione: senza WHERE aggiornerai tutte le righe.
UPDATE customers
SET city = 'Firenze', updated_at = CURRENT_TIMESTAMP
WHERE email = 'luca.bianchi@example.com';
PostgreSQL / MySQL (diversa sintassi):
-- MySQL style
UPDATE customers c
JOIN regions r ON c.region_code = r.code
SET c.tax_rate = r.default_tax
WHERE r.country = 'IT';
-- PostgreSQL style (FROM):
UPDATE customers c
SET tax_rate = r.default_tax
FROM regions r
WHERE c.region_code = r.code AND r.country = 'IT';
DELETE FROM table_name
WHERE condition;
Attenzione: senza WHERE eliminerai tutti i record.
DELETE FROM customers
WHERE last_login < '2018-01-01';
BEGIN;
DELETE FROM orders WHERE status = 'test';
-- verifiche manuali qui...
COMMIT;
-- o se qualcosa va storto
ROLLBACK;
Per evitare duplicati e aggiornare se esiste già (diverso per dialetti):
INSERT INTO customers (email, first_name, last_name, city)
VALUES ('anna.rossi@example.com', 'Anna', 'Rossi', 'Milano')
ON CONFLICT (email) DO UPDATE
SET first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
city = EXCLUDED.city,
updated_at = CURRENT_TIMESTAMP;
INSERT INTO customers (email, first_name, last_name)
VALUES ('anna.rossi@example.com', 'Anna', 'Rossi')
ON DUPLICATE KEY UPDATE
first_name = VALUES(first_name),
last_name = VALUES(last_name);
MERGE INTO customers AS target
USING (VALUES ('anna.rossi@example.com', 'Anna', 'Rossi')) AS src(email, first_name, last_name)
ON target.email = src.email
WHEN MATCHED THEN
UPDATE SET first_name = src.first_name, last_name = src.last_name
WHEN NOT MATCHED THEN
INSERT (email, first_name, last_name) VALUES (src.email, src.first_name, src.last_name);
Per evitare SQL injection, mai concatenare input utente direttamente:
Esempio (pseudocodice):
-- NON FARE
EXECUTE 'INSERT INTO customers (email) VALUES (''' || user_email || ''')';
-- FARE (parametrizzato)
PREPARE stmt (text) AS
INSERT INTO customers (email) VALUES ($1);
EXECUTE stmt ('luca@example.com');
In applicazioni usare API del linguaggio (PDO in PHP, PreparedStatement in Java, psycopg2 in Python).
Constraint: PRIMARY KEY, UNIQUE, NOT NULL, CHECK.
Foreign key: per mantenere coerenza referenziale.
Esempio:
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
city VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Effettuare log delle modifiche importanti e backup regolari prima di operazioni massive.
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
phone VARCHAR(30),
city VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP
);
INSERT INTO customers (email, first_name, last_name, phone, city)
VALUES
('luca.bianchi@example.com', 'Luca', 'Bianchi', '+39333111222', 'Firenze'),
('anna.rossi@example.com', 'Anna', 'Rossi', '+393491234567', 'Milano'),
('marco.verdi@example.com', 'Marco', 'Verdi', NULL, 'Torino');
Aggiungiamo aggiornamento città per Marco:
UPDATE customers
SET city = 'Genova', updated_at = CURRENT_TIMESTAMP
WHERE email = 'marco.verdi@example.com';
Rimuoviamo un contatto di test:
DELETE FROM customers
WHERE email = 'test.user@example.com';
INSERT INTO customers (email, first_name, last_name, phone, city)
VALUES ('luca.bianchi@example.com', 'Luca', 'Bianchi', '+39333111222', 'Firenze')
ON CONFLICT (email) DO UPDATE
SET first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
phone = EXCLUDED.phone,
city = EXCLUDED.city,
updated_at = CURRENT_TIMESTAMP;
Scrivi uno script SQL che aggiunga 100 clienti fittizi usando INSERT multipli (usa generate_series() in PostgreSQL per velocizzare).
Scrivi una transazione che sposti ordini da orders a orders_archive solo per ordini con status = 'cancelled' (uso di BEGIN / COMMIT / ROLLBACK).
Implementa una stored procedure che esegue upsert su customers e ritorna l'id del record (dialetto DB a scelta).
Crea un CHECK constraint che imponga formato internazionale per phone (es. inizio con '+').
Testa sempre le modifiche in un ambiente di staging prima di eseguire su produzione.
Usa transazioni per operazioni multiple correlate.
Proteggi le query con prepared statements per sicurezza e prestazioni.
Pianifica indici se le operazioni di aggiornamento/cancellazione frequenti impattano performance: indici aiutano SELECT, ma rallentano UPDATE/INSERT/DELETE. Valuta trade-off.
Commenti
Posta un commento