El FULL OUTER JOIN completa la família dels joins externs: conserva totes les files de totes dues taules, casin o no. És la unió d'un LEFT JOIN i un RIGHT JOIN en una sola operació.

És també, amb diferència, el JOIN que menys vegades escriuràs. I per una raó interessant que aquesta lliçó explica: en una base de dades amb integritat referencial ben declarada, com la de BotigaVerda, els orfes només poden existir en un costat. Un FULL OUTER JOIN entre dues taules relacionades per una clau forana degenera gairebé sempre en un LEFT JOIN. El seu veritable terreny de joc és en un altre lloc: la conciliació de dues fonts de dades independents, on cap de les dues no mana sobre l'altra.

Contingut

  1. La regla i el diagrama de conjunts
  2. FULL OUTER JOIN sobre BotigaVerda: per què només apareixen orfes en un costat
  3. El cas real: conciliar dues fonts de dades
  4. El patró "només el que no casa en cap dels dos costats"
  5. Emulació en motors que no el suporten
  6. Suport per motor i cost
  7. Errors habituals i consells
  8. Exercicis
  9. Conclusió

  1. La regla i el diagrama de conjunts

flowchart LR
    subgraph R[" "]
        direction LR
        A(("només a l'esquerra<br/>✅ amb NULL a la dreta"))
        I(("casen<br/>✅ resultat"))
        B(("només a la dreta<br/>✅ amb NULL a l'esquerra"))
    end
    style A fill:#d9f0d9,stroke:#2b7a2b,stroke-width:3px
    style I fill:#d9f0d9,stroke:#2b7a2b,stroke-width:3px
    style B fill:#d9f0d9,stroke:#2b7a2b,stroke-width:3px

El quadre complet de la família, ja amb els quatre tipus:

Tipus Esquerra òrfena Casen Dreta òrfena Files del resultat
INNER JOIN casen
LEFT JOIN casen + òrfenes esq.
RIGHT JOIN casen + òrfenes dre.
FULL OUTER JOIN casen + òrfenes esq. + òrfenes dre.

Sintaxi: FULL OUTER JOIN i FULL JOIN són el mateix, perquè OUTER és opcional igual que a LEFT i RIGHT. En aquest curs escrivim FULL OUTER JOIN complet, perquè la seva raresa justifica ser explícits.

I una propietat que el distingeix dels altres dos externs: el FULL OUTER JOIN sí que és commutatiu. A FULL OUTER JOIN B i B FULL OUTER JOIN A retornen el mateix conjunt de files, perquè tots dos costats reben el mateix tracte.

Propietat INNER LEFT RIGHT FULL OUTER
Commutatiu

  1. FULL OUTER JOIN sobre BotigaVerda: per què només apareixen orfes en un costat

Provem el cas més evident: catàleg enfront de vendes.

SELECT p.id AS producte_id,
       p.nom AS producte,
       lc.id AS linia_id,
       lc.quantitat
FROM productes AS p
FULL OUTER JOIN linies_comanda AS lc ON lc.producte_id = p.id
ORDER BY p.id, lc.id;

50 files. Exactament les mateixes que retornava el LEFT JOIN de 03-03:

Consulta Files
productes INNER JOIN linies_comanda 47
productes LEFT JOIN linies_comanda 50
productes FULL OUTER JOIN linies_comanda 50
productes RIGHT JOIN linies_comanda 47

El FULL OUTER JOIN no ha aportat ni una fila sobre el LEFT JOIN. Per què?

Perquè perquè aparegués un orfe pel costat dret hauria d'existir una línia de comanda el producte_id de la qual no correspongués a cap producte. I això és precisament el que la clau forana impedeix:

producte_id INTEGER NOT NULL REFERENCES productes(id) ON DELETE RESTRICT

Dues restriccions actuen alhora:

Restricció Què impedeix
REFERENCES productes(id) Inserir una línia amb un producte_id que no existeixi a productes
NOT NULL Inserir una línia sense producte_id
ON DELETE RESTRICT Esborrar un producte que tingui línies, deixant-les òrfenes
flowchart LR
    A["Pot haver-hi un producte<br/>sense línies de venda?"] -->|"Sí: 13, 19 i 20"| B["orfes<br/>per l'ESQUERRA"]
    C["Pot haver-hi una línia<br/>sense producte?"] -->|"No: ho impedeix la FK"| D["orfes per la DRETA:<br/>impossibles"]

D'aquí en surt una regla general molt útil:

Entre dues taules unides per una clau forana NOT NULL amb integritat referencial declarada, un FULL OUTER JOIN és sempre equivalent a un LEFT JOIN des de la taula pare. Escriure'l és redundant, i a més paga un cost que no necessita.

El mateix passa amb clients i comandes: comandes.client_id és NOT NULL REFERENCES clients(id), així que clients FULL OUTER JOIN comandes retorna les mateixes 23 files que el LEFT JOIN.

L'únic cas de BotigaVerda en què el FULL OUTER sí que aportaria alguna cosa és comandes amb empleats, perquè empleat_id admet NULL:

  • Orfes per l'esquerra: les 10 comandes web sense empleat.
  • Orfes per la dreta: els 5 empleats sense comandes.
  • Total: 10 emparellaments + 10 + 5 = 25 files.

És l'únic FULL OUTER JOIN amb sentit en aquest esquema, i tot i així seria més clar escriure dues consultes separades: "comandes sense comercial" i "empleats sense comandes" responen a preguntes de negoci diferents, i barrejar-les en una taula amb nuls pels dos costats no ajuda ningú.

  1. El cas real: conciliar dues fonts de dades

El FULL OUTER JOIN brilla quan les dues taules no estan unides per una clau forana: quan són dues fonts independents que haurien de coincidir i cal esbrinar en què no coincideixen. Exemples habituals:

Conciliació Font A Font B Què es busca
Catàleg enfront de vendes externes Catàleg propi Fitxer d'un marketplace SKU que no existeixen, productes no publicats
Inventari enfront de comptabilitat Recompte físic de magatzem Sistema comptable Diferències d'existències
Nòmines enfront de directori Sistema de RH Directori d'usuaris Altes i baixes no propagades
Cobraments enfront de factures Extracte bancari Factures emeses Cobraments sense factura, factures sense cobrament

En tots ells la clau és la mateixa: cap de les dues fonts no és l'autoritat. Cadascuna pot tenir files que l'altra no té, i l'objectiu de l'informe és precisament trobar-les.

L'escenari: vendes del marketplace

BotigaVerda ha començat a vendre també en un marketplace extern, que cada mes envia un fitxer CSV amb les unitats venudes per SKU. Carreguem aquest fitxer en una taula temporal:

Avís: vendes_marketplace no forma part de l'esquema de BotigaVerda. És una taula auxiliar creada només per a aquest exemple. No la facis servir a la resta d'exercicis del curs, i esborra-la en acabar (o desconnecta't: en ser TEMP, desapareix amb la sessió).

CREATE TEMP TABLE vendes_marketplace (
    sku     INTEGER,
    unitats INTEGER
);

INSERT INTO vendes_marketplace (sku, unitats) VALUES
( 1, 14), ( 2,  9), ( 3,  6), ( 4, 11), ( 5, 22),
( 6,  4), ( 7,  7), ( 8,  3), ( 9, 12), (10,  5),
(11,  8), (12,  6), (14, 15), (15,  2), (16, 10),
(17,  4), (18, 19), (101, 7), (102, 3);

19 files. Fixa't en dues coses: no hi ha cap clau forana entre sku i productes.id —el fitxer ve d'un altre sistema, no li podem imposar restriccions—, i apareixen dos SKU estranys, el 101 i el 102.

La conciliació completa

SELECT p.id  AS producte_id,
       p.nom AS producte,
       vm.sku,
       vm.unitats
FROM productes AS p
FULL OUTER JOIN vendes_marketplace AS vm ON vm.sku = p.id
ORDER BY COALESCE(p.id, vm.sku);
producte_id producte sku unitats
1 Oli d'oliva verge extra 500 ml 1 14
2 Arròs integral ecològic 1 kg 2 9
3 Mel de tarongina crua 500 g 3 6
4 Pasta d'espelta 500 g 4 11
5 Tomàquet triturat ecològic 400 g 5 22
6 Crema facial d'àloe vera 50 ml 6 4
7 Xampú sòlid de romaní 80 g 7 7
8 Oli corporal d'ametlles 200 ml 8 3
9 Bàlsam labial de calèndula 15 ml 9 12
10 Detergent ecològic concentrat 1 L 10 5
11 Fregall vegetal de lufa (pack 3) 11 8
12 Bosses reutilitzables de cotó (pack 5) 12 6
13 Espelmes de cera de soja (pack 2) (null) (null)
14 Infusió de camamilla ecològica 20 u 14 15
15 Te verd matcha cerimonial 30 g 15 2
16 Kombutxa de gingebre 750 ml 16 10
17 Suc de taronja premsat en fred 1 L 17 4
18 Raspall de dents de bambú 18 19
19 Desodorant natural en barra 50 g (null) (null)
20 Càpsules d'espirulina 120 u (null) (null)
(null) (null) 101 7
(null) (null) 102 3

22 files = 17 emparellaments + 3 productes sense vendes al marketplace + 2 SKU desconeguts.

Ara sí que hi ha orfes pels dos costats, i cadascun explica una història diferent:

  • Els productes 13, 19 i 20 no s'han venut al marketplace. Coincideixen amb els que tampoc no es venen a la botiga pròpia, cosa que reforça el diagnòstic: sense estoc, descatalogat i amb problema comercial.
  • Els SKU 101 i 102 han generat vendes al marketplace però no existeixen al catàleg. Això és una alerta operativa seriosa: pot ser una referència antiga amb una altra numeració, un error de mapatge entre sistemes o vendes que ningú no està imputant a cap producte.

Un detall d'escriptura: l'ORDER BY COALESCE(p.id, vm.sku) ordena per l'identificador "vingui d'on vingui". Si ordenessis només per p.id, les dues files del marketplace tindrien NULL en aquella columna i se n'anirien al final (o al principi, segons NULLS FIRST/LAST, com vas veure a 02-05). COALESCE retorna el primer valor no nul de la llista, i s'estudia a fons a 06-04.

  1. El patró "només el que no casa en cap dels dos costats"

La conciliació completa està bé per revisar, però el que s'envia a operacions és només la llista de discrepàncies. És l'equivalent a l'anti-join de 03-03, ara per partida doble:

SELECT p.id  AS producte_id,
       p.nom AS producte,
       vm.sku,
       vm.unitats
FROM productes AS p
FULL OUTER JOIN vendes_marketplace AS vm ON vm.sku = p.id
WHERE p.id IS NULL
   OR vm.sku IS NULL
ORDER BY COALESCE(p.id, vm.sku);
producte_id producte sku unitats
13 Espelmes de cera de soja (pack 2) (null) (null)
19 Desodorant natural en barra 50 g (null) (null)
20 Càpsules d'espirulina 120 u (null) (null)
(null) (null) 101 7
(null) (null) 102 3

5 files: les tres discrepàncies del catàleg i les dues del fitxer. Això és un informe de conciliació de debò, i en un sistema real arribaria per correu cada matí.

En termes de conjunts, aquest patró retorna la diferència simètrica:

flowchart LR
    subgraph R[" "]
        direction LR
        A(("només catàleg<br/>✅"))
        I(("casen<br/>❌ excloses pel WHERE"))
        B(("només marketplace<br/>✅"))
    end
    style A fill:#d9f0d9,stroke:#2b7a2b,stroke-width:3px
    style I fill:#f8f8f8,stroke:#bbb,stroke-dasharray: 4 4
    style B fill:#d9f0d9,stroke:#2b7a2b,stroke-width:3px

Dos detalls importants d'escriptura:

Detall Per què
L'operador és OR, no AND Amb AND demanaries files on faltessin les dues claus alhora, cosa impossible: tota fila del resultat ve d'almenys un costat. AND retorna sempre 0 files
Es comparen les claus de cada costat p.id i vm.sku. Igual que a l'anti-join simple, cal triar columnes que no puguin ser NULL de forma legítima a les seves taules d'origen

I les tres variants del filtre, segons el que vulguis:

WHERE Retorna Files aquí
(cap) Conciliació completa 22
p.id IS NULL OR vm.sku IS NULL Només discrepàncies (diferència simètrica) 5
vm.sku IS NULL Només el que és al catàleg i no al fitxer 3
p.id IS NULL Només el que és al fitxer i no al catàleg 2

  1. Emulació en motors que no el suporten

MySQL i MariaDB no implementen FULL OUTER JOIN. L'emulació clàssica consisteix a combinar un LEFT JOIN i un RIGHT JOIN amb UNION:

-- Emulació de FULL OUTER JOIN a MySQL
SELECT p.id AS producte_id, p.nom AS producte, vm.sku, vm.unitats
FROM productes AS p
LEFT JOIN vendes_marketplace AS vm ON vm.sku = p.id

UNION

SELECT p.id, p.nom, vm.sku, vm.unitats
FROM productes AS p
RIGHT JOIN vendes_marketplace AS vm ON vm.sku = p.id;

La lògica és directa:

flowchart TD
    A["LEFT JOIN<br/>casen + orfes esquerra<br/>= 20 files"] --> C["UNION<br/>apila i elimina duplicats"]
    B["RIGHT JOIN<br/>casen + orfes dreta<br/>= 19 files"] --> C
    C --> D["22 files<br/>= FULL OUTER JOIN"]

Les 17 files que casen apareixen a totes dues consultes. Per això cal fer servir UNION i no UNION ALL: UNION elimina els duplicats i deixa 20 + 19 − 17 = 22 files. Amb UNION ALL obtindries 39 files, amb les 17 coincidències repetides dues vegades.

UNION, UNION ALL i les seves regles són el tema de la lliçó 03-07; aquí n'hi ha prou de saber que existeix l'emulació i per què necessita eliminar duplicats.

Nota de dialecte: a MySQL l'emulació té una volta de rosca desagradable. Com que UNION compara files completes, dues files que difereixin en qualsevol columna es consideren diferents; si al teu conjunt de dades hi hagués files repetides de forma legítima, UNION les col·lapsaria i perdries informació. L'alternativa robusta és fer LEFT JOIN complet UNION ALL amb només els orfes de la dreta (RIGHT JOIN ... WHERE p.id IS NULL), que no genera solapament i no necessita deduplicar.

  1. Suport per motor i cost

Motor FULL OUTER JOIN Nota
PostgreSQL ✅ Sí Des de versions molt antigues, sense restriccions
MySQL / MariaDB No Cal emular-lo amb UNION de LEFT i RIGHT
SQLite ✅ Sí, des de la 3.39 (juny del 2022) Igual que RIGHT JOIN
SQL Server ✅ Sí Sense restriccions
Oracle ✅ Sí La sintaxi antiga (+) no pot expressar un full outer

Per què es fa servir poc

Quatre raons, en ordre d'importància:

  1. La integritat referencial el fa innecessari dins d'un mateix esquema. És l'argument de la secció 2, i explica la majoria dels casos.
  2. Gairebé sempre el que es vol és una de les dues meitats. "Productes sense vendes" o "vendes sense producte" són preguntes concretes que un LEFT JOIN amb anti-join respon millor, i amb un resultat més llegible.
  3. El resultat és incòmode de llegir. Una taula amb nuls pels dos costats obliga a COALESCE per ordenar, per agrupar i per presentar. Cada columna clau existeix per duplicat.
  4. És el JOIN més car. El motor ha de recórrer totes dues relacions completament i marcar els no emparellats als dos costats: no pot aturar-se abans ni descartar aviat. A PostgreSQL només s'implementa amb hash join o merge join; no existeix un pla de nested loop per a un FULL OUTER JOIN, cosa que de vegades obliga a materialitzar i ordenar tots dos costats. Amb taules grans es nota (mòdul 8).

Regla pràctica: abans d'escriure un FULL OUTER JOIN, pregunta't si de debò necessites els orfes de tots dos costats al mateix resultat. Nou de cada deu vegades la resposta és no, i un LEFT JOIN és més clar i més ràpid. La desena vegada —una conciliació real entre dos sistemes— és exactament per al que existeix.

Errors habituals i consells

  • Fer servir FULL OUTER JOIN entre dues taules unides per una FK NOT NULL. No aporta cap fila sobre el LEFT JOIN i costa més. La integritat referencial ja garanteix que no hi ha orfes del costat fill.
  • Escriure AND en lloc d'OR al filtre de discrepàncies. WHERE p.id IS NULL AND vm.sku IS NULL retorna sempre 0 files: cap fila del resultat no pot faltar pels dos costats alhora.
  • Ordenar per una sola de les dues claus. Les files òrfenes de l'altre costat tenen aquella columna a NULL i se'n van a l'extrem del llistat. Fes servir ORDER BY COALESCE(a.clau, b.clau).
  • Oblidar que les columnes clau estan duplicades. A la conciliació tens p.id i vm.sku. Per presentar un identificador únic cal COALESCE(p.id, vm.sku).
  • Emular-lo amb UNION ALL a MySQL. Duplica totes les files que casen: 39 en comptes de 22 a l'exemple d'aquesta lliçó.
  • Suposar que existeix a MySQL. No existeix, i no està previst. Si el teu SQL ha de ser portable, evita'l.
  • Confondre "sense parella" amb "dada buida". Igual que a 03-03: comprova sempre contra una columna que no pugui ser NULL legítimament a la seva taula d'origen.
  • Consell: comença pel LEFT JOIN i comprova si necessites més. Executa el LEFT, compta files, executa el FULL OUTER i compara. Si el número no canvia, el FULL OUTER sobra.
  • Consell: en una conciliació, afegeix una columna que digui d'on ve cada fila. Amb CASE (mòdul 6) pots etiquetar cada fila com a "només catàleg", "només fitxer" o "coincideix". L'informe es torna autoexplicatiu.
  • Consell: desa el patró de discrepàncies. FULL OUTER JOIN ... WHERE a.clau IS NULL OR b.clau IS NULL és una plantilla que reutilitzaràs cada vegada que dos sistemes hagin de quadrar.

Exercicis

Exercici 1

Executa aquestes dues consultes i compara el nombre de files:

SELECT c.id, c.nom, co.id AS comanda_id
FROM clients AS c
LEFT JOIN comandes AS co ON co.client_id = c.id;

SELECT c.id, c.nom, co.id AS comanda_id
FROM clients AS c
FULL OUTER JOIN comandes AS co ON co.client_id = c.id;
  1. Quantes files retorna cadascuna?
  2. Explica el resultat en termes de les restriccions declarades sobre comandes.client_id.
  3. Què hauria de canviar a l'esquema perquè les dues consultes donessin resultats diferents?

Exercici 2

Sobre la taula temporal vendes_marketplace de la secció 3, escriu dues consultes separades:

  1. Els productes del catàleg que no apareixen al fitxer del marketplace, amb el seu nom, preu i estoc.
  2. Els SKU del fitxer que no existeixen al catàleg, amb les unitats venudes.

Escriu la primera amb un LEFT JOIN i la segona amb un RIGHT JOIN, i després raona: per què en aquest cas resulten més útils dues consultes separades que el FULL OUTER JOIN de la secció 4?

Exercici 3

La teva empresa migra a MySQL una consulta de conciliació escrita en PostgreSQL:

SELECT p.id AS producte_id, p.nom AS producte, vm.sku, vm.unitats
FROM productes AS p
FULL OUTER JOIN vendes_marketplace AS vm ON vm.sku = p.id
WHERE p.id IS NULL OR vm.sku IS NULL;
  1. Reescriu-la per a MySQL fent servir UNION.
  2. Podries fer servir UNION ALL en aquesta reescriptura concreta? Raona la resposta mirant què retorna cada meitat.

Solucions

Solució 1

1. Totes dues retornen 23 files.

2. La columna està declarada així:

client_id INTEGER NOT NULL REFERENCES clients(id) ON DELETE RESTRICT

Les tres parts actuen juntes:

  • REFERENCES clients(id) impedeix inserir una comanda amb un client_id inexistent.
  • NOT NULL impedeix inserir una comanda sense client.
  • ON DELETE RESTRICT impedeix esborrar un client que tingui comandes, que és l'altra forma de generar orfes.

Conclusió: no pot existir cap comanda òrfena, així que el costat dret no aporta res i el FULL OUTER JOIN degenera en el LEFT JOIN. Les 23 files són les mateixes: 20 comandes + 3 clients sense comandes.

3. N'hi hauria prou que client_id admetés NULL —per exemple, per registrar comandes de convidats sense compte—. Aquestes comandes no casarien amb cap client i apareixerien com a orfes per la dreta, només visibles amb FULL OUTER JOIN (o amb RIGHT JOIN). És exactament la situació de comandes.empleat_id, que sí que admet nuls: comandes FULL OUTER JOIN empleats retorna 25 files enfront de les 20 del LEFT JOIN.

Solució 2

1. Productes del catàleg que no són al fitxer:

SELECT p.id,
       p.nom AS producte,
       p.preu,
       p.stock
FROM productes AS p
LEFT JOIN vendes_marketplace AS vm ON vm.sku = p.id
WHERE vm.sku IS NULL
ORDER BY p.id;
id producte preu stock
13 Espelmes de cera de soja (pack 2) 13.75 0
19 Desodorant natural en barra 50 g 7.80 75
20 Càpsules d'espirulina 120 u 16.40 55

2. SKU del fitxer que no existeixen al catàleg:

SELECT vm.sku,
       vm.unitats
FROM productes AS p
RIGHT JOIN vendes_marketplace AS vm ON vm.sku = p.id
WHERE p.id IS NULL
ORDER BY vm.sku;
sku unitats
101 7
102 3

Per què dues consultes separades són més útils aquí:

Motiu Explicació
Columnes diferents Un producte sense vendes interessa amb el seu preu i el seu estoc; un SKU desconegut interessa amb les unitats venudes. En una sola taula caldria retornar la unió de tots dos jocs de columnes, amb la meitat a NULL a cada fila
Destinataris diferents La primera llista va a màrqueting; la segona, a l'equip d'integracions. Són dues incidències amb dos responsables
Urgència diferent Un producte sense vendes és una observació comercial; un SKU venut que no existeix al catàleg és un error de dades que cal corregir avui
Llegibilitat Cada consulta té un significat únic i s'explica sola. El FULL OUTER obliga a llegir els nuls per saber de quin tipus és cada fila

El FULL OUTER JOIN continua sent útil per a la visió de conjunt —el quadre de 22 files de la secció 3, per revisar d'un cop d'ull—, però la feina operativa es despatxa millor amb dues consultes dirigides.

Solució 3

1. Reescriptura per a MySQL:

-- Meitat esquerra: productes del catàleg sense SKU al fitxer
SELECT p.id AS producte_id, p.nom AS producte, vm.sku, vm.unitats
FROM productes AS p
LEFT JOIN vendes_marketplace AS vm ON vm.sku = p.id
WHERE vm.sku IS NULL

UNION

-- Meitat dreta: SKU del fitxer sense producte al catàleg
SELECT p.id, p.nom, vm.sku, vm.unitats
FROM productes AS p
RIGHT JOIN vendes_marketplace AS vm ON vm.sku = p.id
WHERE p.id IS NULL;

Retorna les mateixes 5 files que la versió PostgreSQL.

2. Es pot fer servir UNION ALL? Sí, i a més és preferible.

El raonament és el que importa: UNION (sense ALL) cal quan les dues meitats poden produir les mateixes files, i s'han d'eliminar els duplicats. Aquest és el cas de l'emulació general de la secció 5, on tots dos JOIN retornen les 17 files que casen.

Aquí no passa. Cada meitat porta el seu propi WHERE que la restringeix als orfes del seu costat:

Meitat Filtre Retorna Solapament
Esquerra vm.sku IS NULL 3 files: productes sense SKU
Dreta p.id IS NULL 2 files: SKU sense producte cap

Cap fila no pot complir les dues condicions alhora, així que els conjunts són disjunts i no hi ha res a deduplicar. UNION ALL és més ràpid perquè s'estalvia el pas d'ordenació o de taula hash que UNION necessita per detectar duplicats. És un exemple perfecte de la regla que veuràs a 03-07: fes servir UNION ALL llevat que tinguis una raó concreta per eliminar duplicats.

Conclusió

Tanques la família dels joins externs:

  • El FULL OUTER JOIN conserva les files òrfenes de tots dos costats: és un LEFT i un RIGHT alhora. És l'únic join extern commutatiu.
  • Sobre BotigaVerda gairebé mai no aporta res, i saps explicar per què: la integritat referencial (REFERENCES + NOT NULL + ON DELETE RESTRICT) impedeix que existeixin orfes del costat fill. productes FULL OUTER JOIN linies_comanda retorna les mateixes 50 files que el LEFT JOIN.
  • El seu terreny real és la conciliació de dues fonts independents, on cap no mana sobre l'altra: catàleg contra fitxer d'un marketplace, inventari contra comptabilitat, extracte bancari contra factures.
  • Has construït aquesta conciliació completa (22 files) i l'informe de discrepàncies amb el patró WHERE a.clau IS NULL OR b.clau IS NULL (5 files): tres productes que el marketplace no ven i dos SKU que no existeixen al catàleg. Recorda: l'operador és OR, mai AND.
  • Saps emular-lo amb UNION d'un LEFT JOIN i un RIGHT JOIN per a MySQL, i per què aquesta emulació necessita eliminar duplicats llevat que cada meitat estigui restringida als seus propis orfes.
  • I coneixes el seu cost: no admet pla de nested loop, obliga a recórrer totes dues relacions senceres i produeix un resultat que necessita COALESCE per a gairebé tot. Fes-lo servir quan de debò necessitis els dos costats.

A la lliçó següent, SELF JOIN i CROSS JOIN, veurem els dos JOIN "rars" que més confonen qui comença. El SELF JOIN et permetrà recórrer per fi les dues relacions reflexives de BotigaVerda: la jerarquia d'empleats amb cap_id —on tornaràs a necessitar un LEFT JOIN per no perdre la Rosa, la directora sense cap— i la xarxa de referits de clients. El CROSS JOIN, que fins ara només ha aparegut com a accident, es convertirà en una eina deliberada per generar combinacions completes.

Curs de SQL

Mòdul 1: Introducció a SQL

Mòdul 2: Consultes bàsiques de SQL

Mòdul 3: Treballar amb múltiples taules

Mòdul 4: Filtratge avançat de dades

Mòdul 5: Manipulació de dades

Mòdul 6: Funcions avançades de SQL

Mòdul 7: Subconsultes i consultes imbricades

Mòdul 8: Índexs i optimització del rendiment

Mòdul 9: Transaccions i concurrència

Mòdul 10: Temes avançats

Mòdul 11: SQL a la pràctica

Mòdul 12: Projecte final

© Copyright 2026. Tots els drets reservats