Common Table Expressions, eller CTE för kort, är helt enkelt en teknik för att skapa en temporär uppsättning poster som kan refereras till i en INSERT-, SELECT-, UPDATE- eller DELETE-sats.
Vanliga tabelluttryck introducerades av Microsoft i SQL Server 2005. De lagras inte som objekt i databasminnet eftersom deras livslängd är lika med exekveringstiden för frågan. Så snart en fråga är klar tas de bort från databasminnet. CTE kan refereras i en fråga så många gånger du vill och de kan också vara självrefererande.
Låt oss skapa en databas med en elevtabell och infoga några dummy-studentposter i den. Vi kommer att använda denna databas för att skriva CTE-frågor. Som alltid se till att du är väl säkerhetskopierad innan du experimenterar med en ny kod. Se den här artikeln om SQL-säkerhetskopiering om du inte är säker.
Kör följande frågor 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);
Låt oss nu skapa ett mycket enkelt vanligt tabelluttryck. Denna CTE kommer att innehålla register över alla elever som är födda före 1 januari 1985. Ta en titt på följande manus.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' )
För att skapa en CTE måste du börja med nyckelordet 'WITH' följt av namnet på CTE och 'AS' nyckelordet.
Därefter, inom parentes, måste du skriva frågan som returnerar de poster som CTE tillfälligt kommer att lagra. I skriptet ovan skapade vi en CTE med namnet "OldStudents".
Observera dock att om du försöker köra ovanstående fråga får du ett felmeddelande. Detta beror på att när du väl har skapat en CTE måste du omedelbart använda den.
Låt oss välja alla poster från vår nyskapade "OldStudents" CTE. Prova följande skript på din server.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ) SELECT * FROM OldStudents
Ovanstående skript kommer att hämta följande uppsättning poster:
Beräknar aggregat via CTE
Precis som tabeller kan du utföra aggregerade funktioner på CTE. Låt oss ta en titt på ett annat exempel 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 exemplet ovan skapade vi en CTE som heter SumofScores. Denna CTE innehåller summan av värdena som lagras i kolumnen total_score i elevtabellen. Resultatet grupperas efter könskolumnen. Data som lagras av CTE ser ut så här i minnet:
Därefter utförde vi AVG-funktionen i kolumnen "SumScore" i CTE. Det slutliga resultatet av skriptet blir genomsnittet 2400 och 2730, dvs. 2565.
Detta är lite mer komplicerat än det föregående exemplet men visar konceptet med CTE tydligare.
Märkning av kolumner i CTE
I föregående exempel lade vi till ett alias till den andra kolumnen i CTE. Vi döpte om det till "SumScore". Detta är ett sätt att märka kolumner i CTE och liknar alias för tabellkolumner.
Det finns dock ett annat sätt att definiera kolumnnamn i CTE. Ta en titt på följande fråga.
USE schooldb; WITH SumofScores(Gender, SumScore) AS ( SELECT gender, SUM(total_score) FROM student GROUP BY gender ) SELECT AVG (SumScore) From SumofScores
I det här skriptet lade vi till kolumnnamnen för "SumofScores" CTE inom parentes efter CTE-namnet. Varje kolumnnamn avgränsas med ett kommatecken.
Om du tittar på SELECT-satsen efter CTE, kan du se att vi då refererar till "SumScore"-kolumnen som vi skapade inom parentes efter CTE-namnet.
Skapa flera CTE:er
Alla exemplen hittills har bara använt ett enda gemensamt tabelluttryck för tydlighetens skull. Du kan skapa en lista över CTE samtidigt och sedan använda dem alla i kombination i den slutliga resultatuppsättningen.
Detta förklaras bäst med hjälp av ett exempel. Ta en titt på följande skript nedan.
Här kommer vi att skapa två CTE:er. Den första CTE kommer att lagra alla uppgifter om elever födda före 1 januari 1985. Den andra CTE kommer att innehålla alla uppgifter om elever födda 1 januari 1985 eller senare.
Efter det kommer vi att använda utvalda uttalanden för att hämta alla poster från båda CTE:erna. De hämtade posterna kommer att slås samman med UNION-satsen. Slutligen kommer den sammanslagna posten att sorteras i stigande ordning efter födelsedatum.
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 ovanstående SQL-fråga skapade vi två CTE:er:"OldStudents" och "YoungStudents". Det är värt att nämna att du inte behöver använda nyckelordet "WITH" med varje CTE. Du behöver bara använda det före den första CTE i skriptet, efter det kan du skapa valfritt antal CTE genom att separera dem med ett kommatecken.
Ovanstående skript hämtar följande resultat: