sql >> Database teknologi >  >> RDS >> Oracle

selvforenet vs indre sammenføjning

Jeg finder det nyttigt at tænke på alle tabellerne i en SELECT-sætning som repræsenterende deres egne datasæt.

Før du har anvendt nogen betingelser, kan du tænke på, at hvert datasæt er komplet (f.eks. hele tabellen).

En joinforbindelse er blot en af ​​flere måder at begynde at forfine disse datasæt for at finde den information, du virkelig ønsker.

Selvom et databaseskema kan være designet med bestemte relationer i tankerne (Primærnøgle <-> Fremmednøgle), eksisterer disse relationer egentlig kun i sammenhæng med en bestemt forespørgsel. Forespørgselsskriveren kan relatere, hvad de vil, til hvad de vil. Jeg giver et eksempel på dette senere...

En INNER JOIN forbinder to tabeller med hinanden. Der er ofte flere JOIN-operationer i én forespørgsel for at kæde flere tabeller sammen. Det kan blive så kompliceret, som det skal. Som et simpelt eksempel kan du overveje følgende tre tabeller...

STUDENT

| STUDENTID | LASTNAME | FIRSTNAME |
------------------------------------
      1     |  Smith   |   John
      2     |  Patel   |  Sanjay
      3     |   Lee    |  Kevin
      4     |  Jackson |  Steven
 
ENROLLMENT

| ENROLLMENT ID | STUDENTID | CLASSID |
---------------------------------------
        1       |     2     |    3
        2       |     3     |    1
        3       |     4     |    2
 
CLASS

| CLASSID | COURSE | PROFESSOR |
--------------------------------
     1    | CS 101 |   Smith
     2    | CS 201 |  Ghandi
     3    | CS 301 |  McDavid
     4    | CS 401 |  Martinez
 

STUDENT-tabellen og KLASSE-tabellen blev designet til at relatere til hinanden gennem TILMELDINGStabellen. Denne type tabel kaldes en Junction Table .

For at skrive en forespørgsel for at vise alle elever og de klasser, de er tilmeldt, skal man bruge to indre sammenføjninger...

SELECT stud.LASTNAME, stud.FIRSTNAME, class.COURSE, class.PROFESSOR
FROM STUDENT stud
INNER JOIN ENROLLMENT enr
    ON stud.STUDENTID = enr.STUDENTID
INNER JOIN CLASS class
    ON class.CLASSID = enr.CLASSID;
 

Læs ovenstående nøje, og du skal se, hvad der sker. Hvad du får til gengæld er følgende datasæt...

| LASTNAME | FIRSTNAME | COURSE | PROFESSOR | --------------------------------------------- Patel | Sanjay | CS 301 | McDavid Lee | Kevin | CS 101 | Smith Jackson | Steven | CS 201 | Ghandi

Ved at bruge JOIN-klausulerne har vi begrænset datasættene i alle tre tabeller til kun dem, der matcher hinanden. "Kampene" defineres ved hjælp af ON klausuler. Bemærk, at hvis du kørte denne forespørgsel, ville du ikke se CLASSID 4-rækken fra CLASS-tabellen eller STUDENTID 1-rækken fra STUDENT-tabellen, fordi disse ID'er ikke eksisterer i matchene (i dette tilfælde ENROLLMENT-tabellen). Se "VENSTRE"/"HØJRE"/"FULD YDRE" JOINs for at læse mere om, hvordan du får det til at fungere lidt anderledes.

Bemærk venligst, at der ifølge mine kommentarer om "forhold" tidligere er ingen grund hvorfor du ikke kunne køre en forespørgsel relateret til STUDENT-tabellen og CLASS-tabellen direkte på LASTNAME og PROFESSOR kolonnerne. Disse to kolonner matcher datatype, og se godt på det! De har endda en værdi til fælles! Dette ville sandsynligvis være et mærkeligt datasæt at få til gengæld. Min pointe er, at det kan lade sig gøre, og du ved aldrig, hvilke behov du måtte have i fremtiden for interessante forbindelser i dine data. Forstå designet af databasen, men tænk ikke på "relationer" som værende regler, der ikke kan ignoreres.

I mellemtiden... JOINDER SELV!

Overvej følgende tabel...

PERSON

| PERSONID | FAMILYID |  NAME  |
--------------------------------
      1    |     1    |  John
      2    |     1    | Brynn
      3    |     2    | Arpan
      4    |     2    | Steve
      5    |     2    |  Tim
      6    |     3    | Becca
 

Hvis du følte dig så tilbøjelig til at lave en database over alle de mennesker, du kender, og hvilke der er i samme familie, kan det være sådan, det ser ud.

Hvis du ville returnere én person, f.eks. PERSONID 4, ville du skrive...

SELECT * FROM PERSON WHERE PERSONID = 4;
 

Du ville lære, at han er i familien med FAMILYID 2. Så for at finde alle af PERSONERNE i hans familie ville du skrive...

SELECT * FROM PERSON WHERE FAMILYID = 2;
 

Færdig og færdig! SQL kan selvfølgelig opnå dette i én forespørgsel ved at bruge, du gættede rigtigt, en SELF JOIN.

Hvad der virkelig udløser behovet for et SELV-JOIN her er, at tabellen indeholder en unik kolonne (PERSONID) og en kolonne, der fungerer som en slags "Kategori" (FAMILYID). Dette koncept kaldes Kardinalitet og repræsenterer i dette tilfælde en en til mange eller 1:M forhold. Der er kun én af hver PERSON men der er mange PERSONER i en FAMILIE .

Så det, vi ønsker at returnere, er alt af medlemmerne af en familie, hvis én medlem af familiens PERSONID er kendt...

SELECT fam.*
FROM PERSON per
JOIN PERSON fam
    ON per.FamilyID = fam.FamilyID
WHERE per.PERSONID = 4;
 

Her er, hvad du ville få...

| PERSONID | FAMILYID | NAME | -------------------------------- 3 | 2 | Arpan 4 | 2 | Steve 5 | 2 | Tim

Lad os bemærke et par ting. Ordene SELV JOIN forekommer ikke nogen steder. Det er fordi en SELV JOIN er bare et koncept. Ordet JOIN i forespørgslen ovenfor kunne have været en LEFT JOIN i stedet, og andre ting ville være sket. Pointen med en SELV JOIN er, at du bruger den samme tabel to gange.

Overvej min sæbekasse fra før på datasæt. Her er vi startet med datasættet fra PERSON-tabellen to gange. Hverken forekomst af datasættet påvirker det andet, medmindre vi siger, det gør det.

Lad os starte i bunden af ​​forespørgslen. Den pr. datasættet begrænses til kun de rækker, hvor PERSONID =4. Ved at kende tabellen, kender vi, som vil returnere præcis én række. FAMILYID-kolonnen i den række har en værdi på 2.

I ON-klausulen begrænser vi fam datasæt (som på dette tidspunkt stadig er hele PERSON-tabellen) til kun de rækker, hvor værdien af ​​FAMILYID matcher en eller flere af FAMILYID'erne for pr. datasæt. Som vi diskuterede, kender vi pr. datasættet har kun én række, derfor én FAMILYID-værdi. Derfor familien datasættet indeholder nu kun rækker, hvor FAMILYID =2.

Til sidst, øverst i forespørgslen vælger vi alle rækkerne i fam datasæt.

Voila! To forespørgsler i én.

Afslutningsvis en INNER JOIN er en af ​​flere slags JOIN-operationer. Jeg ville stærkt foreslå at læse videre i LEFT, RIGHT og FULL OUTER JOINs (som tilsammen kaldes OUTER JOINs ). Jeg gik personligt glip af en jobmulighed for at have et svagt kendskab til OUTER JOINs én gang og vil ikke lade det ske igen!

ET JEGVENDIGT er simpelthen enhver JOIN-operation, hvor du relaterer en tabel til sig selv. Den måde du vælger at JOIN det bord til sig selv kan bruge en INNER JOIN eller en YDRE JOIN. Bemærk, at med en SELV JOIN , for ikke at forvirre din SQL-motor, skal du brug tabelaliasser (fam og per fra oven. Opret hvad der giver mening for din forespørgsel), ellers er der ingen måde at skelne mellem de forskellige versioner af samme tabel.

Nu hvor du forstår forskellen, åbner dit sind godt og bredt og indser, at en enkelt forespørgsel kunne indeholde alle forskellige slags JOINs på én gang. Det er kun et spørgsmål om, hvilke data du vil have, og hvordan du skal vride og bøje din forespørgsel for at få den. Hvis du finder dig selv at køre en forespørgsel og tager resultatet af den forespørgsel og bruger den som input til en anden forespørgsel, kan du sandsynligvis bruge en JOIN for at gøre det til én forespørgsel i stedet for.

For at lege med SQL, prøv at besøge W3Schools.com Der er en lokalt gemt database der med en masse tabeller, der er designet til at relatere til hinanden på forskellige måder, og den er fyldt med data! Du kan CREATE, DROP, INSERT, UPDATE og SELECT alt, hvad du vil, og returnere databasen tilbage til dens standard til enhver tid. Prøv alle slags SQL for at eksperimentere med forskellige tricks. Jeg har selv lært meget der.

Beklager, hvis dette var lidt ordrigt, men jeg kæmpede personligt med konceptet JOINs, da jeg begyndte at lære SQL og forklare et koncept ved at bruge en masse andre komplekse begreber, fik mig til at hænge fast. Bedst at starte i bunden nogle gange.

Jeg håber det hjælper. Hvis du kan lægge JOINs i din baglomme, kan du arbejde magi med SQL!

God forespørgsel!



  1. MySQL, kopiering af tabelfiler giver anledning til FEJL 1017 (HY000):Kan ikke finde fil:selvom den er der

  2. Sådan tilslutter du dig tre tabeller i Codeigniter

  3. PL/SQL ORA-01422:nøjagtig hentning returnerer mere end det anmodede antal rækker

  4. Hvordan udskriver man en mysql-forespørgsel korrekt i zend?