Ce face WITH (CTE)
O expresie de tabel comună (CTE) este un SELECT cu nume, scris în fața comenzii principale cu WITH. În comanda principală îl folosești ca pe un tabel obișnuit. Poți defini mai multe CTE-uri separate prin virgulă, iar fiecare le poate folosi pe cele de dinaintea lui.
În SQLite, WITH merge în fața lui SELECT, INSERT, UPDATE și DELETE. Un CTE poate avea propria listă de coloane și poate conține direct VALUES, ceea ce e util pentru câteva date de test fără să creezi un tabel.
Din 3.35.0 poți scrie AS MATERIALIZED (rezultatul se calculează o dată și se păstrează) sau AS NOT MATERIALIZED (SQLite îl poate integra în interogarea principală). Fără indicație, SQLite alege singur; un CTE folosit de mai multe ori este de obicei materializat.
Parametri
| Parametru | Descriere |
|---|---|
nume |
Numele sub care folosești rezultatul în restul comenzii. |
(coloane) |
Opțional: numele coloanelor rezultatului. |
MATERIALIZED |
Opțional (3.35.0+): sugerează cum să fie calculat CTE-ul. |
Exemple
Exemplele de pe această pagină pornesc de la datele de mai jos. Rulează mai întâi acest cod, apoi exemplul.
CREATE TABLE vanzari (
id INTEGER PRIMARY KEY,
oras TEXT NOT NULL,
agent TEXT NOT NULL,
suma INTEGER NOT NULL
);
INSERT INTO vanzari (oras, agent, suma) VALUES
('Iași', 'Ana', 1200),
('Iași', 'Radu', 800),
('Cluj', 'Elena', 1500),
('Cluj', 'Dan', 400),
('Brașov', 'Mara', 950),
('Iași', 'Ana', 600);
Exemplul 1: Totaluri pe oraș, apoi filtrare
CTE-ul totale calculează suma pe oraș; interogarea principală păstrează doar orașele cu peste 1.000 de lei.
WITH totale AS (
SELECT oras, SUM(suma) AS total
FROM vanzari
GROUP BY oras
)
SELECT oras, total
FROM totale
WHERE total > 1000
ORDER BY total DESC;
Rezultat
╭──────┬───────╮
│ oras │ total │
╞══════╪═══════╡
│ Iași │ 2600 │
│ Cluj │ 1900 │
╰──────┴───────╯
Exemplul 2: Două CTE-uri înlănțuite
pe_agent adună vânzările fiecărui agent, iar medie calculează media acestor totaluri. La final rămân agenții peste medie (media este 1.090 de lei).
WITH pe_agent AS (
SELECT agent, SUM(suma) AS total FROM vanzari GROUP BY agent
),
medie AS (
SELECT AVG(total) AS valoare FROM pe_agent
)
SELECT agent, total, (SELECT valoare FROM medie) AS media
FROM pe_agent
WHERE total > (SELECT valoare FROM medie)
ORDER BY total DESC;
Rezultat
╭───────┬───────┬────────╮
│ agent │ total │ media │
╞═══════╪═══════╪════════╡
│ Ana │ 1800 │ 1090.0 │
│ Elena │ 1500 │ 1090.0 │
╰───────┴───────┴────────╯
Exemplul 3: CTE cu VALUES și CTE înaintea lui UPDATE
Prima comandă folosește un CTE construit din VALUES, cu nume de coloane date în paranteză. A doua mărește cu 10% vânzările din orașele cu un singur agent; după UPDATE, vânzarea din Brașov a ajuns la 1.045 de lei.
WITH tinte (oras, obiectiv) AS (
VALUES ('Iași', 2500), ('Cluj', 2000), ('Brașov', 1000)
)
SELECT t.oras, t.obiectiv, SUM(v.suma) AS realizat
FROM tinte t JOIN vanzari v ON v.oras = t.oras
GROUP BY t.oras
ORDER BY t.oras;
WITH orase_mici AS (
SELECT oras FROM vanzari GROUP BY oras HAVING COUNT(DISTINCT agent) = 1
)
UPDATE vanzari SET suma = suma * 11 / 10
WHERE oras IN (SELECT oras FROM orase_mici);
SELECT oras, agent, suma FROM vanzari WHERE oras = 'Brașov';
Rezultat
╭────────┬──────────┬──────────╮
│ oras │ obiectiv │ realizat │
╞════════╪══════════╪══════════╡
│ Brașov │ 1000 │ 950 │
│ Cluj │ 2000 │ 1900 │
│ Iași │ 2500 │ 2600 │
╰────────┴──────────┴──────────╯
╭────────┬───────┬──────╮
│ oras │ agent │ suma │
╞════════╪═══════╪══════╡
│ Brașov │ Mara │ 1045 │
╰────────┴───────┴──────╯
Greșeli frecvente
- Pui virgulă după ultimul CTE, înainte de
SELECT. Virgula separă doar CTE-urile între ele. - Folosești un CTE într-o altă comandă. Numele există doar în comanda în care l-ai definit; pentru reutilizare creează o vedere (
CREATE VIEW). - Pui
WITHîn mijlocul unuiINSERT ... SELECTși primești eroare. ScrieWITHla începutul comenzii:WITH x AS (...) INSERT INTO t SELECT ... FROM x;.
Comenzi înrudite
WITH RECURSIVE: Un CTE care se folosește pe el însuși: generează serii de numere sau de date și parcurge ierarhii (șef–subordonat, categorii).ROW_NUMBER, RANK, LAG (funcții fereastră): Calculează pentru fiecare rând un număr de ordine, un loc în clasament sau valoarea din rândul vecin, fără să grupeze rândurile.CREATE VIEW: Salvează un SELECT sub un nume, ca să îl folosești apoi ca pe un tabel. În SQLite, vederile sunt doar pentru citire.EXPLAIN QUERY PLAN: Arată cum va executa SQLite o interogare: ce tabele citește în întregime (SCAN) și unde folosește un index (SEARCH).