Šajā rakstā detalizēti paskatīsimies uz pašu izplatītāko tabulu kombinēšanas veidu – INNER JOIN.
For english speaking only check SQL join types.
Inner Join
Diemžēl man nav īstas skaidrības kā latviski tiek tulkots Inner Join. Līdz ar to esmu spiests visā šai rakstā uz to tā arī atsaukties.
Inner Join tiek lietots, lai atlasītu tos un tikai tos ierakstus no abām tabulām, kur abu tabulu ieraksti atbilst kombinēšanas nosacījumam. Visbiežāk kombinēšanas nosacījums ir tāds, ka pirmās tabulas noteiktas kolonas vērtībām ir jāsakrīt ar otrās tabulas noteiktas kolonas vērtībām. Iedomājamies, ka mums ir tabulas A un B, kā attēlots iepriekšējā rakstā. Tādā gadījumā Inner Join rezultāts grafiski izskatītos šādi:
Sintakse
SELECT <kolonu saraksts> FROM <kreisās puses tabula> [INNER] JOIN <labās puses tabula> ON <kombinēšanas nosacījums>
- SELECT un FROM klauzas ir aprakstītas iepriekšējā tēmā Vienkāršs SQL Select teikums.
- Atslēgas vārdu INNER bieži vienkārši atmet un nelieto, bet tas tādā gadījumā vienalga ir INNER join.
- Pēc atslēgas vārda ON tiek rakstīts kombinēšanas nosacījums. Tas ne vienmēr ir tikai divu kolonu salīdzinājums uz vienādību, bet nosacījumus var kombinēt izmantojot loģiskos operatorus AND, OR, NOT.
Piemēri ir balstīti uz tām pašām tabulām un datiem, kas rakstā par CROSS JOIN.
Piemērs 1. Atlasa personas kodu, vārdu un adreses pilsētu katrai personai.
SQL> SELECT prs_personas_kods, prs_vards, adr_pilseta 2 FROM personas 3 INNER JOIN adreses ON prs_adr_id = adr_id; PRS_PERSONA PRS_VARDS ADR_PILSETA ----------- ---------------------------------------- ------------- 23456789012 PĒTERIS TALSI 45678901234 KĀRLIS TALSI 34567890123 ANNA TALSI
INNER join gadījumā ir vienalga, vai papildus nosacījumus raksta kombinēšanas nosacījumā vai WHERE klauzā, protams, atceroties, ka WHERE klauzas nosacījumi tiek nosacīti pielikti klāt ar loģisko AND. Nākamajos 2 piemēros tas ir ilustrēts:
Piemērs 2. Atlasa personas kodu, vārdu un adreses pilsētu katrai personai kombinēšanas nosacījumam pievienojot papildus, ka vārdam jāsākas ar P.
SQL> SELECT prs_personas_kods, prs_vards, adr_pilseta 2 FROM personas 3 INNER JOIN adreses ON prs_adr_id = adr_id 4 AND prs_vards LIKE 'P%'; PRS_PERSONA PRS_VARDS ADR_PILSETA ----------- ---------------------------------------- ------------- 23456789012 PĒTERIS TALSI
Piemērs 3. Atlasa personas kodu, vārdu un adreses pilsētu katrai personai šoreiz WHERE klauzā pievienojot papildus nosacījumu, ka vārdam jāsākas ar P. Kā redzams rezultāts ir ekvivalents iepriekšējam Piemēram 2.
SQL> SELECT prs_personas_kods, prs_vards, adr_pilseta 2 FROM personas 3 INNER JOIN adreses ON prs_adr_id = adr_id 4 WHERE prs_vards LIKE 'P%'; PRS_PERSONA PRS_VARDS ADR_PILSETA ----------- ---------------------------------------- ---------- 23456789012 PĒTERIS TALSI
Kas notiek, ja kombinēšanas nosacījumā izmanto loģisko OR, var redzēt 4. piemērā. Šeit ir labi redzams, ka patiesībā INNER JOIN ir apakškopa no CROSS JOIN, tas ir, tiek atlasīts arī Dekarta reizinājums visiem tiem Personu ierakstiem, kam vārds sākas ar P.
Piemērs 4. Jābūt ļoti uzmanīgiem kombinēšanas nosacījumā izmantojot loģisko operatoru OR, tas var novest pie interesantām sekām.
SQL> SELECT prs_personas_kods, prs_vards, adr_pilseta 2 FROM personas 3 INNER JOIN adreses 4 ON prs_adr_id = adr_id OR prs_vards LIKE 'P%'; PRS_PERSONA PRS_VARDS ADR_PILSETA ----------- ---------------------------------------- --------------- 23456789012 PĒTERIS RĪGA 23456789012 PĒTERIS TALSI 34567890123 ANNA TALSI 45678901234 KĀRLIS TALSI 23456789012 PĒTERIS VALMIERA
Kas notiek tad, ja kombinēšanas nosacījums vienmēr ir patiess, var redzēt 5. piemērā. Mēs esam atpakaļ pie Dekarta reizinājuma.
Piemērs 5. Ja nosacījums vienmēr ir patiess, tad INNER JOIN degradējās uz CROSS JOIN (Dekarta rezinājumu).
SQL> SELECT prs_personas_kods, prs_vards, adr_pilseta 2 FROM personas 3 INNER JOIN adreses ON 1=1; PRS_PERSONA PRS_VARDS ADR_PILSETA ----------- ---------------------------------------- ------------- 12345678910 JĀNIS RĪGA 23456789012 PĒTERIS RĪGA 34567890123 ANNA RĪGA 45678901234 KĀRLIS RĪGA 12345678910 JĀNIS TALSI 23456789012 PĒTERIS TALSI 34567890123 ANNA TALSI 45678901234 KĀRLIS TALSI 12345678910 JĀNIS VALMIERA 23456789012 PĒTERIS VALMIERA 34567890123 ANNA VALMIERA 45678901234 KĀRLIS VALMIERA 12 rows selected.
6. piemērā ir parādīts, ka kombinēšanas nosacījumam ne vienmēr ir jābūt vienādībai. Šajā gadījumā tiek atlasītas personas, kuru adrešu identfikatori nesakrīt ar adreses identifikatoru adreses tabulā. Ir vērts pievērst arī uzmanību tam, ka tā persona, kam lauks prs_adr_id ir NULL netiek atlasīta, jo jebkāda salīdzināšana ar NULL vienmēr dod rezultātu Aplams.
Piemērs 6. Nosacījums var arī nebūt vienādība. Atlasam tos ierakstus no personām, kam adreses identifikators nesakrīt ar identifikatoru adreses tabulā.
SQL> SELECT prs_personas_kods, prs_vards, adr_pilseta 2 FROM personas 3 INNER JOIN adreses ON prs_adr_id <> adr_id 4 / PRS_PERSONA PRS_VARDS ADR_PILSETA ----------- ---------------------------------------- -------------- 23456789012 PĒTERIS RĪGA 34567890123 ANNA RĪGA 45678901234 KĀRLIS RĪGA 23456789012 PĒTERIS VALMIERA 34567890123 ANNA VALMIERA 45678901234 KĀRLIS VALMIERA
Inner Join, protams, var lietot kombinējot tabulu pašu ar sevi. Nākošajā piemērā redzams, ka tabula personas tiek kombinēta ar sevi trīs reizes – vienā gadījumā, kā bērns, otrā kā māte, trešajā kā tēvs. Tātad šis piemērs ilustrē SELF JOIN (kombinēšanu pašam ar sevi), kā arī to, ka, protams, vienā SQL teikumā var kombinēt vairākas tabulas.
Piemērs 7. Piemērs kombinēšanai tabulai ar sevi (SELF JOIN) un vairāku tabulu kombinēšanai vienā SQL teikumā.
SQL> SELECT 2 tevs.prs_vards "Teva Vārds", 3 mate.prs_vards "Mātes vārds", 4 berns.prs_vards "Bērna vārds" 5 FROM personas berns 6 INNER JOIN personas tevs ON berns.prs_tevs_id = tevs.prs_id 7 INNER JOIN personas mate ON berns.prs_mate_id = mate.prs_id; Teva Vārds Mātes vārds Bērna vārds ----------------- ------------- ------------- PĒTERIS ANNA KĀRLIS
Alternatīvā sintakse
Šim kombinēšanas veidam var arī izmantot alternatīvo sintaksi, kas ir šāda:
SELECT <kolonu saraksts> FROM <kreisās puses tabula>, <labās puses tabula> WHERE <kombinēšanas nosacījums>
Šai sintaksē kombinēšanas nosacījumi tiek rakstīti kopā ar pārējiem nosacījumiem. Visus SQL vaicājumus, kur ir Inner Join, var aizstāt ar šo sintaksi un rezultāts būs tieši tāds pats. Ik pa laikam forumos izraisās diskusijas, kura sintakse ir labāka? Skat. piemēru Should one use ANSI join syntax when writing an Oracle application? It kā šai alternatīvajai sintaksei ir lielākas iespējas iegūst Dekarta reizinājumu, ja aizmirsts kombinēšanas nosacījums, taču, rakstot Inner Join, FROM klauzā nav uzreiz redzamas visas izmantotās tabulas. Mans personīgais viedoklis ir tāds, ka šeit nav pilnīgi viennozīmīgas atbildes, pēc principa vienam patīk māte, otram meita, trešajam kleita 🙂 Man personīgi labāk patīk sintakse, kad visas tabulas raksta FROM klauzā ļoti vienkārša iemesla dēļ – pirms vairāk kā 10 gadiem es tā sāku darīt un tikai relatīvi nesen esmu spiests lietot kombinēšanas sintaksi ar atslēgas vārdiem Inner un Outer.
Piemērs 8. Šis ir ekvivalents piemēram 2. Atlasa personas kodu, vārdu un adreses pilsētu katrai personai kombinēšanas nosacījumam pievienojot papildus, ka vārdam jāsākas ar P. Abas tabulas ir minētas FROM klauzā.
SQL> SELECT prs_personas_kods, prs_vards, adr_pilseta 2 FROM personas, adreses 3 WHERE prs_adr_id = adr_id 4 AND prs_vards LIKE 'P%'; PRS_PERSONA PRS_VARDS ADR_PILSETA ----------- ---------------------------------------- ------------ 23456789012 PĒTERIS TALSI
Piemērs 9. Šis ir ekvivalents piemēram 7.Piemērs kombinēšanai tabulai ar sevi (SELF JOIN) un vairāku tabulu kombinēšanai vienā SQL teikumā. Viss trīs tabulas ir minētas FROM klauzā.
SQL> SELECT 2 tevs.prs_vards "Teva Vārds", 3 mate.prs_vards "Mātes vārds", 4 berns.prs_vards "Bērna vārds" 5 FROM 6 personas berns, 7 personas tevs, 8 personas mate 9 WHERE berns.prs_tevs_id = tevs.prs_id 10 AND berns.prs_mate_id = mate.prs_id; Teva Vārds Mātes vārds Bērna vārds ----------------- ------------- ------------- PĒTERIS ANNA KĀRLIS
Kas jāatceras papildus:
- Datubāzes ir radītas tam, lai tās kombinētu ierakstus. Tieši ierakstu kombinēšana ir viens no ļoti lielajiem ieguvumiem, ko datubāzes mums dod. Veidojot datubāzes struktūru tiek veikta normalizācija, tas ir, darbības, lai pēc iespējas izvairītos no datu dublicēšanas, savukārt datu ieguves laikā, lai atlasītu informāciju cilvēkiem lasāmā formātā, kombinēšana ir neaizstājama. Tā kā Inner Join ir viens no visbiežāk izmantotajiem kombinēšanas veidiem, tad jāatceras, ka kombinēšana ir jāveic datu bāzē, nevis uz klienta, piemēram, vienā ciklā kasot ārā ierakstu pa ierakstam no vienas tabulas un tad iekšējā ciklā braucot cauri saistītās tabulas ierakstiem.
- Pārējās klauzas (Group By, Having, Order By), kas ir pieminētas rakstā Vienkāršs SQL Select teikums ir spēkā un darbojas arī tabulu kombinēšanas vaicājumiem.
Turpmākā lasāmviela
- Retrieval: Multiple Tables and Aggregation – Part 1 – nodaļa no grāmatas Mastering Oracle SQL and SQL *Plus, ko uzrakstījis Lex de Haan.
P.S. Izskatās, ka vairākos rakstos Inner Join tiek saukts par IEKŠĒJO SAVIENOJUMU, piemēram,
- rakstā par Access pamatiem;
- LAKAs terminu vārdnīcā (piedāvājums).
Tādējādi, tā kā nekā labāka nav, tad droši vien tā arī var lietot iekšējais savienojums.
Paldies tiešām noderēja 🙂
Es vēlētos, lai sākumā būtu dota tabula visa pilnībā un tad uz šīs tabulas izpildīti vaicājumu. Tā varētu izsekot rezultātiem, kas netiek ņemti un kas tiek paņemti un izvadīti.
Diemžēl, domāju, ka tā nav īsti laba ideja, jo šis raksts ir tikai viens no visu savienojumu saimes. Un pirmajā no detalizētajiem aprakstiem – Dekarta reizinājumā es definēju testa datus un tabulas un pēc tam konsekventi tās lietoju visur ar atsauci, ka tos izmantoju. Drukāt tās atkal un atkal būtu lieka telpas šķiešana, bet nekas jau nekavē otrā logā/tabā atvērt piemērus un skatīties uz visiem reizē.