Wspólne wyrażenia tabelowe, w skrócie CTE, to po prostu technika tworzenia tymczasowego zestawu rekordów, do których można się odwoływać w instrukcjach INSERT, SELECT, UPDATE lub DELETE.
Wspólne wyrażenia tabelowe zostały wprowadzone przez Microsoft w SQL Server 2005. Nie są one przechowywane jako obiekty w pamięci bazy danych, ponieważ ich żywotność jest równa czasowi wykonania zapytania. Po zakończeniu zapytania są one usuwane z pamięci bazy danych. Do CTE można odwoływać się w zapytaniu tyle razy, ile chcesz, a także mogą odnosić się do siebie.
Stwórzmy bazę danych z tabelą uczniów i wstawmy do niej kilka fikcyjnych rekordów uczniów. Użyjemy tej bazy danych do pisania zapytań CTE. Jak zawsze, upewnij się, że masz dobrą kopię zapasową przed eksperymentowaniem z nowym kodem. Zobacz ten artykuł na temat tworzenia kopii zapasowych SQL, jeśli nie masz pewności.
Wykonaj następujące zapytania na swoim serwerze.
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);
Teraz stwórzmy bardzo proste, wspólne wyrażenie tabelowe. Ten CTE będzie zawierał zapisy wszystkich uczniów, którzy urodzili się przed 1 stycznia 1985 r. Spójrz na poniższy skrypt.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' )
Aby utworzyć CTE, musisz zacząć od słowa kluczowego „Z”, po którym następuje nazwa CTE i słowo kluczowe „AS”.
Następnie w nawiasie należy wpisać zapytanie, które zwraca rekordy, które CTE będzie tymczasowo przechowywać. W powyższym skrypcie stworzyliśmy CTE o nazwie „OldStudents”.
Pamiętaj jednak, że jeśli spróbujesz wykonać powyższe zapytanie, otrzymasz błąd. Dzieje się tak, ponieważ po utworzeniu CTE musisz natychmiast go użyć.
Wybierzmy wszystkie rekordy z naszego nowo utworzonego CTE „OldStudents”. Wypróbuj następujący skrypt na swoim serwerze.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ) SELECT * FROM OldStudents
Powyższy skrypt pobierze następujący zestaw rekordów:
Obliczanie agregacji za pomocą CTE
Podobnie jak tabele, możesz wykonywać funkcje agregujące na CTE. Rzućmy okiem na inny przykład CTE.
USE schooldb; WITH SumofScores AS ( SELECT gender, SUM(total_score) as SumScore FROM student GROUP BY gender ) SELECT AVG (SumScore) FROM SumofScores
W powyższym przykładzie stworzyliśmy CTE o nazwie SumofScores. To CTE zawiera sumę wartości przechowywanych w kolumnie total_score tabeli uczniów. Wynik jest pogrupowany według kolumny płci. Dane przechowywane przez CTE wyglądają w pamięci tak:
Następnie wykonaliśmy funkcję AVG w kolumnie „SumScore” CTE. Ostatecznym wynikiem skryptu będzie średnia 2400 i 2730, czyli 2565.
Jest to nieco bardziej skomplikowane niż w poprzednim przykładzie, ale wyraźniej pokazuje koncepcję CTE.
Oznaczanie kolumn w CTE
W poprzednim przykładzie dodaliśmy alias do drugiej kolumny CTE. Zmieniliśmy jego nazwę na „SumScore”. Jest to jeden ze sposobów oznaczania kolumn w CTE i jest podobny do aliasów kolumn tabeli.
Istnieje jednak inny sposób definiowania nazw kolumn w CTE. Spójrz na następujące zapytanie.
USE schooldb; WITH SumofScores(Gender, SumScore) AS ( SELECT gender, SUM(total_score) FROM student GROUP BY gender ) SELECT AVG (SumScore) From SumofScores
W tym skrypcie dodaliśmy nazwy kolumn CTE „SumofScores” w nawiasie po nazwie CTE. Każda nazwa kolumny jest oddzielona przecinkiem.
Jeśli spojrzysz na instrukcję SELECT po CTE, zobaczysz, że odwołujemy się wtedy do kolumny „SumScore”, którą utworzyliśmy w nawiasie po nazwie CTE.
Tworzenie wielu CTE
Wszystkie dotychczasowe przykłady używały tylko jednego wspólnego wyrażenia tabelowego dla jasności. Możesz utworzyć listę CTE w tym samym czasie, a następnie użyć ich wszystkich razem w końcowym zestawie wyników.
Najlepiej to wyjaśnić na przykładzie. Spójrz na poniższy skrypt.
Tutaj stworzymy dwa CTE. Pierwszy CTE będzie zawierał wszystkie rekordy uczniów urodzonych przed 1 stycznia 1985 r. Drugi CTE będzie zawierał wszystkie rekordy uczniów urodzonych 1 stycznia 1985 r. lub później.
Następnie użyjemy instrukcji select, aby pobrać wszystkie rekordy z obu CTE. Pobrane rekordy zostaną połączone za pomocą instrukcji UNION. Na koniec scalony rekord zostanie posortowany w porządku rosnącym według daty urodzenia.
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
W powyższym zapytaniu SQL stworzyliśmy dwa CTE:„OldStudents” i „YoungStudents”. Warto wspomnieć, że nie musisz używać słowa kluczowego „Z” przy każdym CTE. Musisz go użyć tylko przed pierwszym CTE w skrypcie, po czym możesz utworzyć dowolną liczbę CTE, oddzielając je przecinkiem.
Powyższy skrypt pobiera następujące wyniki: