Produs cartezian (Cross Join)
Cu inner join este posibil să omiteți ON. SQL interpretează acest lucru ca pe o cerere – corectă din punct de vedere sintactic – de a combina fiecare înregistrare a tabelului din stânga cu fiecare înregistrare a tabelului din dreapta. Va returna un număr mare de rânduri: produsul numărului de rânduri din cele două tabele.
Acest tip special de inner join se numește produs cartezian sau CROSS JOIN. Produsul cartezian este o operație elementară a algebrei relaționale, care este fundația tuturor implementărilor rDBMS.
-- toate persoanele combinate cu toate persoanele de contact (unele implementări înlocuiesc
-- cuvântul cheie 'JOIN' cu o virgulă)
SELECT p.firstname, p.lastname, c.contact_type, c.contact_value
FROM person p
JOIN contact c -- missing ON keyword: p X c will be created
ORDER BY p.lastname, p.firstname, c.contact_type DESC, c.contact_value;
-- count the resulting rows
SELECT count(*)
FROM person p
JOIN contact c;
Fiți atent atunci; dacă omiteți neintenționat termenul ON, rezultatul va fi mult mai mare decât se aștepta. Dacă, de exemplu, primul tabel conține 10.000 de înregistrări, iar al doilea 20.000 de înregistrări, rezultatul va conține 200 milioane de rânduri.
Situația n:m
Cum putem crea o listă de persoane și hobby-urile lor? Amintiți-vă: o persoană poate avea mai multe hobby-uri și mai multe persoane pot avea același hobby. Deci nu există o legătură directă între persoane și hobby-uri. Între cele două tabele, am creat un al treilea, person_hobby. Deține id-ul persoanelor, precum și id-ul hobby-urilor.
Trebuie să „mergem” de la person la person_hobby și de acolo la hobby.
-- persoane combinate cu hobby-urile lor
SELECT p.id p_id, p.firstname, p.lastname, h.hobbyname, h.id h_id
FROM person p
JOIN person_hobby ph ON p.id = ph.person_id
JOIN hobby h ON ph.hobby_id = h.id
ORDER BY p.lastname, p.firstname, h.hobbyname;
Vă rugăm să rețineți că nicio coloană a tabelului person_hobby nu merge la rezultat. Acest tabel acționează numai în timpul etapelor intermediare de execuție. Nici măcar id-ul coloanei sale nu este de interes.
Unii oameni nu au niciun hobby. Deoarece am efectuat un INNER JOIN, acestea nu fac parte din lista de mai sus. Dacă vrem să vedem în listă și persoane fără hobby-uri, trebuie să facem ceea ce am mai făcut: folosiți LEFT OUTER JOIN în loc de INNER JOIN.
-- TOATE persoanele plus hobby-urile lor (dacă au)
SELECT p.id p_id, p.firstname, p.lastname, h.hobbyname, h.id h_id
FROM person p
LEFT JOIN person_hobby ph ON p.id = ph.person_id
LEFT JOIN hobby h ON ph.hobby_id = h.id
ORDER BY p.lastname, p.firstname, h.hobbyname;
Sugestie: Dacă este necesar, putem combina orice fel de join cu orice alt tip de join în fiecare secvență dorită, de exemplu: LEFT OUTER cu FULL OUTER cu INNER … .
Mai multe detalii
Criteriile pentru operațiunile de unire nu se limitează la formularea obișnuită:
SELECT ...
FROM table_1 t1
JOIN table_2 t2 ON t1.id = t2.fk
...
În primul rând, putem folosi orice coloană, nu numai coloanele cheie primară și cheie externă. Într-unul dintre exemplele de mai sus, am folosit numele de familie pentru un join. Numele este de tipul caracter și nu are semnificația vreunei chei. Pentru a evita performanța slabă, unele SGBD limitează utilizarea coloanelor la cele care au un index.
În al doilea rând, comparatorul nu este limitat la semnul egal. Putem folosi orice operator semnificativ, de exemplu, „mai mare decât” pentru valori numerice.
-- Care persoană are greutatea corporală mai mare - limitată la „de Winter” pentru claritate
SELECT p1.id, p1.firstname as "is heavier", p1.weight, p2.id, p2.firstname as "than", p2.weight
FROM person p1
JOIN person p2 ON p1.weight > p2.weight
WHERE p1.lastname = 'de Winter'
AND p2.lastname = 'de Winter'
ORDER BY p1.weight desc, p2.weight desc;
În al treilea rând, putem folosi o funcție arbitrară.
-- nume scurte vs. nume lungi
SELECT p1.firstname, p1.lastname as "shorter lastname", p2.firstname, p2.lastname
FROM person p1
JOIN person p2 ON LENGTH(p1.lastname) < LENGTH(p2.lastname)
-- la fel ORDER BY poate folosi funcții
ORDER BY length(p1.lastname), length(p2.lastname);
(Include texte din Wikibooks traduse și adaptate de Nicolae Sfetcu)
Lasă un răspuns