Common Table Expressions, eller CTE for kort, er simpelthen en teknik til at skabe et midlertidigt sæt poster, der kan refereres til i en INSERT-, SELECT-, UPDATE- eller DELETE-sætning.
Almindelige tabeludtryk blev introduceret af Microsoft i SQL Server 2005. De gemmes ikke som objekter i databasehukommelsen, da deres levetid er lig med udførelsestiden for forespørgslen. Så snart en forespørgsel er fuldført, fjernes de fra databasehukommelsen. Der kan refereres til CTE i en forespørgsel så mange gange, som du vil, og de kan også være selvrefererende.
Lad os oprette en database med en elevtabel og indsætte nogle dummy-elevposter i den. Vi vil bruge denne database til at skrive CTE-forespørgsler. Som altid skal du være sikker på, at du er godt sikkerhedskopieret, før du eksperimenterer med en ny kode. Se denne artikel om SQL backup, hvis du ikke er sikker.
Udfør følgende forespørgsler på din server.
CREATE DATABASE schooldb CREATE TABLE student ( id INT PRIMARY KEY, name VARCHAR(50) NOT NULL, gender VARCHAR(50) NOT NULL, DOB datetime NOT NULL, total_score INT NOT NULL, ) INSERT INTO student VALUES (1, 'Jolly', 'Female', '12-JUN-1989', 500), (2, 'Jon', 'Male', '02-FEB-1974', 545), (3, 'Sara', 'Female', '07-MAR-1988', 600), (4, 'Laura', 'Female', '22-DEC-1981', 400), (5, 'Alan', 'Male', '29-JUL-1993', 500), (6, 'Kate', 'Female', '03-JAN-1985', 500), (7, 'Joseph', 'Male', '09-APR-1982', 643), (8, 'Mice', 'Male', '16-AUG-1974', 543), (9, 'Wise', 'Male', '11-NOV-1987', 499), (10, 'Elis', 'Female', '28-OCT-1990', 400);
Lad os nu skabe et meget simpelt fælles bordudtryk. Denne CTE vil indeholde optegnelser over alle elever, der er født før 1. januar 1985. Tag et kig på følgende script.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' )
For at oprette en CTE skal du starte med 'WITH' søgeord efterfulgt af navnet på CTE og 'AS' søgeord.
Dernæst skal du inden for parentesen skrive forespørgslen, som returnerer de poster, som CTE midlertidigt vil gemme. I ovenstående script oprettede vi en CTE ved navn "OldStudents".
Bemærk dog, at hvis du forsøger at udføre ovenstående forespørgsel, vil du få en fejl. Dette skyldes, at når du først har oprettet en CTE, skal du straks bruge den.
Lad os vælge alle posterne fra vores nyoprettede "OldStudents" CTE. Prøv følgende script på din server.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ) SELECT * FROM OldStudents
Ovenstående script vil hente følgende sæt poster:
Beregning af aggregat via CTE
Ligesom tabeller kan du udføre aggregerede funktioner på CTE. Lad os tage et kig på et andet eksempel på CTE.
USE schooldb; WITH SumofScores AS ( SELECT gender, SUM(total_score) as SumScore FROM student GROUP BY gender ) SELECT AVG (SumScore) FROM SumofScores
I ovenstående eksempel oprettede vi en CTE ved navn SumofScores. Denne CTE indeholder summen af værdierne gemt i kolonnen total_score i elevtabellen. Resultatet er grupperet efter kønskolonnen. Dataene gemt af CTE ser sådan ud i hukommelsen:
Dernæst udførte vi AVG-funktionen på "SumScore"-kolonnen i CTE. Det endelige resultat af scriptet vil være gennemsnittet på 2400 og 2730, dvs. 2565.
Dette er lidt mere kompliceret end det foregående eksempel, men demonstrerer konceptet CTE mere tydeligt.
Mærkning af kolonner i CTE
I det foregående eksempel tilføjede vi et alias til den anden kolonne i CTE. Vi omdøbte det til "SumScore". Dette er en måde at mærke kolonner på i CTE og ligner tabelkolonnealiasser.
Der er dog en anden måde at definere kolonnenavne i CTE. Tag et kig på følgende forespørgsel.
USE schooldb; WITH SumofScores(Gender, SumScore) AS ( SELECT gender, SUM(total_score) FROM student GROUP BY gender ) SELECT AVG (SumScore) From SumofScores
I dette script tilføjede vi kolonnenavnene for "SumofScores" CTE i parentes efter CTE-navnet. Hvert kolonnenavn er adskilt af et komma.
Hvis du ser på SELECT-sætningen efter CTE, kan du se, at vi så refererer til "SumScore"-kolonnen, som vi oprettede i parentes efter CTE-navnet.
Oprettelse af flere CTE'er
Alle eksemplerne hidtil har kun brugt et enkelt fælles tabeludtryk for klarhedens skyld. Du kan oprette en liste over CTE'er på samme tid og derefter bruge dem alle sammen i det endelige resultatsæt.
Dette forklares bedst ved hjælp af et eksempel. Tag et kig på følgende script nedenfor.
Her vil vi oprette to CTE'er. Den første CTE vil gemme alle optegnelser for elever født før 1. januar 1985. Den anden CTE vil indeholde alle optegnelser for elever født den 1. januar 1985 eller senere.
Derefter vil vi bruge udvalgte erklæringer til at hente alle poster fra begge CTE'er. De hentede poster vil blive flettet sammen ved hjælp af UNION-sætning. Endelig vil den flettede post blive sorteret i stigende rækkefølge efter fødselsdato.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ), YoungStudents AS ( SELECT * FROM student WHERE DOB >= '1985-01-01' ) (SELECT * FROM OldStudents UNION SELECT * FROM YoungStudents) ORDER BY DOB
I ovenstående SQL-forespørgsel oprettede vi to CTE'er:"OldStudents" og "YoungStudents". Det er værd at nævne, at du ikke behøver at bruge søgeordet "WITH" med hver CTE. Du skal kun bruge det før den første CTE i scriptet, derefter kan du oprette et hvilket som helst antal CTE'er ved at adskille dem med et komma.
Ovenstående script henter følgende resultater: