Ten artykuł jest pierwszym z serii o podstawach wyrażeń tabelowych w języku T-SQL. Skoncentruję się głównie na czterech typach nazwanych wyrażeń tabelowych, które są znane w T-SQL jako tabele pochodne, wspólne wyrażenia tabelowe (CTE), widoki i wbudowane funkcje z wartościami tabelarycznymi (wbudowane TVF).
Do napisania tej serii zainspirował mnie mój dobry przyjaciel Grant Fritchey, którego znam od wielu lat. Jak wielokrotnie podkreśla Grant, wiele osób używających typowych wyrażeń tabelowych w T-SQL uważa, że SQL Server utrzymuje wewnętrzny zestaw wyników zapytania i że powodem tego przekonania jest użycie terminu table w nazwie konstruktu. Kiedy ten temat pojawia się w dyskusjach społeczności, często ludzie twierdzą, że użycie terminu tabela w nazwie konstruktu jest niewłaściwe, ponieważ tak naprawdę nie jest to tabela. Istnieją nawet sugestie, aby rozpocząć kampanię nazewniczą w nadziei na przyszłą zmianę nazwy dla tej konstrukcji, przynajmniej w T-SQL. Niektóre z sugestii obejmują wyrażenie zapytania , widok wbudowany , widok na poziomie instrukcji , i inni.
Być może dla niektórych będzie to zaskoczeniem, ale tak naprawdę uważam, że używa się terminu tabela we wspólnym wyrażeniu tabeli jako bardzo właściwe. W rzeczywistości uważam, że używa się terminu wyrażenie tabelowe w stosownych przypadkach. Według mnie najlepszym sposobem na opisanie, czym jest CTE w T-SQL, jest nazwane wyrażenie tabelowe . To samo dotyczy tego, co T-SQL nazywa tabelami pochodnymi (konkretna konstrukcja języka w przeciwieństwie do ogólnej idei), widokami i wbudowanymi funkcjami TVF. Wszystkie są nazwanymi wyrażeniami tabelowymi.
Jeśli możesz ze mną trochę znieść, podam w tym artykule uzasadnienie mojego poglądu na rzeczy. Przyszło mi do głowy, że zarówno zamieszanie w nazewnictwie, jak i zamieszanie wokół tego, czy istnieje aspekt trwałości wyrażeń tabelowych, można rozwiązać dzięki lepszemu zrozumieniu podstaw naszej dziedziny systemów zarządzania relacyjnymi bazami danych. Te podstawy to teoria relacyjna, jak odnosi się do niej SQL (język standardowy) oraz jak dialekt T-SQL używany w implementacjach SQL Server i Azure SQL Database odnosi się do obu.
Na początek chcesz udzielić odpowiedzi na następujące pytania:
- Co oznacza niezależność danych fizycznych zasada w modelu relacyjnym oznacza?
- Co to jest tabela w SQL i jaki jest jej odpowiednik w modelu relacyjnym?
- Jaka jest własność domknięcia algebry relacyjnej?
- Co to jest wyrażenie tabelowe i jaki jest odpowiednik w modelu relacyjnym?
Gdy będziesz w stanie poprawnie odpowiedzieć na powyższe pytania, najprawdopodobniej znajdziesz użycie terminu nazwane wyrażenie tabelowe odpowiednio dla wyżej wymienionych konstrukcji (co T-SQL nazywa tabelami pochodnymi, CTE, widokami i wbudowanymi funkcjami TVF).
Nie chcę brzmieć, jakbym miał bardzo głębokie zrozumienie teorii relacyjnej. Moje doświadczenie to T-SQL. Przyznaję, że jest o wiele więcej rzeczy, których nie wiem na temat teorii relacji niż ja, i że niektóre rzeczy, o których myślę, że wiem, po prostu nie są takie. Kiedy czytam pisma C.J. Dates na ten temat, czuję, że ledwo dotykam powierzchni tego, co trzeba wiedzieć, i że mógłbym i powinienem starać się to lepiej zrozumieć. Uznaję i mocno wierzę, że dobre zrozumienie teorii relacyjnej przekłada się bezpośrednio na lepsze zrozumienie SQL i T-SQL oraz na pisanie lepszego, dokładniejszego i bardziej niezawodnego kodu T-SQL. Każdemu, kto wybrał dane jako swoją karierę, polecam lekturę SQL and Relational Theory:How to Write Accurate SQL Code 3rd Edition autorstwa C.J. Date (O'Reilly 2015).
W pierwszej części tej serii chcę wyjaśnić, w jaki sposób używam terminów wyrażenie tabelowe i nazwane wyrażenie tabelowe , co jest zgodne z użyciem tego terminu przez firmę Date i niestety nie jest zgodne z zastosowaniem tego terminu przez standard SQL. Aby to osiągnąć, przedstawię trochę tła z teorii relacji i standardu SQL. Ale tak jak powiedziałem, polecam lekturę książki Date'a, aby naprawdę szczegółowo omówić ten temat.
Zacznę od wyjaśnienia, co oznacza zasada fizycznej niezależności danych. Następnie wyjaśnię, czym jest tabela w SQL i jej odpowiednik w teorii relacji. Następnie wyjaśnię, co oznacza właściwość domknięcia algebry relacyjnej. Kiedy już masz rozsądne pojęcie, czym jest tabela i co oznacza właściwość closure, całkiem łatwo jest zrozumieć, czym jest wyrażenie tabeli. Skoncentruję się następnie na szczegółach w T-SQL. Mam wiele do powiedzenia na temat podstaw wyrażeń tabelowych w języku T-SQL — zarówno pod względem podejścia koncepcyjnego, jak i szczegółów implementacji, w tym reprezentacji fizycznej i kwestii dostrajania zapytań.
Uważam, że ten temat jest fascynujący i bardzo praktyczny po zagłębieniu się w szczegóły wdrożenia. Właściwie mam tyle do powiedzenia na ten temat, że nie jestem pewien, ile części ostatecznie będzie zawierała ta seria. Z dużą dozą pewności mogę powiedzieć, że będzie wiele części. Prawdopodobnie więcej niż jeden i mniej niż 100. W przyszłych częściach zajmę się poszczególnymi typami nazwanych wyrażeń tabelowych, zagadnieniami dotyczącymi modyfikacji, aspektami inline, aspektami porządkowania, korelacjami i nie tylko.
W moich przykładach użyję przykładowej bazy danych o nazwie TSQLV5. Skrypt, który tworzy i wypełnia tę bazę danych, oraz jego diagram ER można znaleźć tutaj.
Fizyczna niezależność danych
Fizyczna niezależność danych to zasada w teorii relacyjnej, która mówi, że fizyczne szczegóły implementacji powinny być ukryte lub niewidoczne dla użytkownika wysyłającego zapytania do systemu zarządzania relacyjną bazą danych. W zapytaniach użytkownicy powinni skoncentrować się na co muszą używać operacji logicznych opartych na algebrze relacyjnej, w przeciwieństwie do jak w celu uzyskania danych. Nie powinni martwić się o strukturę, dostęp i przetwarzanie danych. Takie fizyczne szczegóły implementacji zwykle różnią się znacznie pomiędzy różnymi implementacjami (produkty RDBMS). Nawet przy tym samym RDBMS fizyczne szczegóły implementacji czasami zmieniają się między różnymi wersjami i kompilacjami. Ideą stojącą za zasadą fizycznej niezależności danych w teorii jest ochrona inwestycji użytkownika poprzez wyeliminowanie konieczności rewizji rozwiązań podczas uaktualniania systemu RDBMS do nowej wersji lub nawet podczas migracji z jednego systemu RDBMS do innego. Jak zapewne dobrze wiesz, w praktyce sprawy nie są takie proste, ale to temat na inną dyskusję.
Co to jest stół?
Jeśli od jakiegoś czasu pracujesz z T-SQL lub jakimkolwiek innym dialektem SQL, nauczysz się intuicyjnie rozumieć, czym jest tabela. Problem polega na tym, że bez podstaw teorii relacji często intuicyjne rozumienie nie jest zbyt dokładne. Typowym błędem jest to, że intuicyjnie skupiamy się na fizycznych szczegółach implementacji. Na przykład, gdy myślisz o tym, czym jest tabela, myślisz o tabeli jako o strukturze logicznej (zestawie wierszy), czy też o szczegółach fizycznej implementacji na używanej platformie (w SQL Server , strony, zakresy, stos a indeks klastrowy, indeksy nieklastrowe itd.)? Jako użytkownik piszący kod SQL w celu zapytania tabeli, zgodnie z zasadą fizycznej niezależności danych, powinieneś myśleć o tabeli jako o strukturze logicznej i pozwolić RDBMS-om martwić się o fizyczne szczegóły implementacji. Cofnijmy się więc o krok i spróbujmy dowiedzieć się, czym jest stół.
Tabela jest w SQL odpowiednikiem głównej struktury w teorii relacji — relacji. Aby uprościć sprawę i ograniczyć zakres mojego pokrycia, nie zamierzam zagłębiać się w rozróżnienie między zmienną relacyjną a wartością relacji. Jeśli zastosujesz się do moich zaleceń i przeczytasz książkę Dates, bardzo szybko uzyskasz jasny obraz takich subtelności.
Relacja ma nagłówek i treść.
Nagłówek relacji to zestaw atrybutów . W matematycznej teorii zbiorów zbiór nie ma porządku ani duplikatów. Powinieneś identyfikować atrybut po nazwie, a nie na jakiejś pozycji. W związku z tym nazwy atrybutów muszą być niepowtarzalne.
Czy potrafisz zidentyfikować odpowiednik atrybutu w SQL? Prawdopodobnie zgadłeś, że to kolumna . Jednak SQL faktycznie ma pojęcie kolejności swoich kolumn na podstawie ich kolejności pojawiania się w instrukcji CREATE TABLE. Na przykład, oto instrukcja CREATE TABLE dla tabeli Sales.Shippers w bazie danych TSQLV5:
CREATE TABLE Sales.Shippers ( shipperid INT NOT NULL IDENTITY, companyname NVARCHAR(40) NOT NULL, phone NVARCHAR(24) NOT NULL, CONSTRAINT PK_Shippers PRIMARY KEY(shipperid) );
Zapytaj tabelę za pomocą znanego SELECT *
, jak tak:
SELECT * FROM Sales.Shippers;
Kiedy uruchomiłem to zapytanie w moim systemie, otrzymałem następujące dane wyjściowe:
shipperid companyname phone ---------- -------------- --------------- 1 Shipper GVSUA (503) 555-0137 2 Shipper ETYNR (425) 555-0136 3 Shipper ZHISN (415) 555-0138
SQL gwarantuje, że kolumny zostaną zwrócone od lewej do prawej na podstawie kolejności definicji. Wkrótce wyjaśnię, co dzieje się z rzędami. SQL umożliwia nawet odwoływanie się do pozycji porządkowej kolumny z listy SELECT w klauzuli ORDER BY, tak jak to (nie, że ja polecam tę praktykę, ani Aaron Bertrand):
SELECT shipperid, companyname, phone FROM Sales.Shippers ORDER BY 2;
To zapytanie generuje następujące dane wyjściowe:
shipperid companyname phone ---------- -------------- --------------- 2 Shipper ETYNR (425) 555-0136 1 Shipper GVSUA (503) 555-0137 3 Shipper ZHISN (415) 555-0138
Ciało relacji to zbiór krotek . Przypomnijmy ponownie, że zestaw nie ma kolejności ani duplikatów. Dlatego relacja musi mieć co najmniej jeden klucz kandydujący, który pozwala jednoznacznie zidentyfikować krotkę. Odpowiednikiem SQL dla krotki jest wiersz . Jednak w SQL nie musisz definiować klucza w tabeli, a jeśli tego nie zrobisz, możesz skończyć z zduplikowanymi wierszami. Nawet jeśli masz zdefiniowany klucz w tabeli, możesz uzyskać zduplikowane wiersze zwrócone z zapytania względem tabeli. Oto przykład:
SELECT country FROM HR.Employees;
To zapytanie generuje następujące dane wyjściowe:
country -------- USA USA USA USA UK UK UK USA UK
To zapytanie nie daje wyniku relacyjnego ze względu na możliwość zduplikowania wierszy. Podczas gdy teoria relacyjna opiera się na teorii mnogości, SQL opiera się na teorii wielozbiorów. Multiset (czyli superset lub torba) może mieć duplikaty. SQL daje narzędzie do eliminowania duplikatów za pomocą klauzuli DISTINCT, na przykład:
SELECT DISTINCT country FROM HR.Employees;
To zapytanie generuje następujące dane wyjściowe:
country -------- UK USA
To, co SQL utrzymuje z teorii relacji w odniesieniu do ciała tabeli, to właściwość bez kolejności. O ile nie dodasz klauzuli ORDER BY w zapytaniu, nie masz żadnej gwarancji, że wynik będzie miał określoną kolejność w wierszach. Tak więc treść powyższego wyniku zapytania jest relacyjna, przynajmniej w tym sensie, że nie ma duplikatów i nie ma gwarantowanej kolejności.
Załóżmy, że wysyłasz zapytanie do tabeli w SQL Server i nie zawierasz klauzuli ORDER BY w zapytaniu. Czy oczekujesz, że SQL Server zawsze będzie zwracał wiersze w określonej kolejności jako zachowanie gwarantowane? Wiele osób to robi. Wielu uważa, że zawsze otrzymasz wiersze na podstawie kolejności indeksów klastrowanych. To dobry przykład ignorowania zasady fizycznej niezależności danych i robienia założeń opartych na intuicji, a być może na podstawie zaobserwowanych zachowań w przeszłości. Microsoft wie, że zapytanie SQL bez klauzuli ORDER BY nie gwarantuje żadnej kolejności między wierszami wyników, a zatem nawet jeśli na poziomie fizycznym dane znajdują się w strukturze indeksu, SQL Server nie musi przetwarzać danych w indeksie zamówienie. W pewnych warunkach fizycznych może to zrobić, ale w innych warunkach fizycznych może tego nie robić. Pamiętaj również, że fizyczne szczegóły implementacji mogą się zmieniać między różnymi wersjami i kompilacjami produktu. Jeśli chcesz zagwarantować, że zapytanie zwróci wiersze wyników w określonej kolejności, jedynym sposobem zagwarantowania tego jest wprowadzenie klauzuli ORDER BY w najbardziej zewnętrznym zapytaniu.
Jak zapewne się domyślasz, projektanci SQL tak naprawdę nie uważali, by podążanie za teorią relacyjną było priorytetem. A to, co tutaj opisałem, to tylko kilka przykładów. Jest ich znacznie więcej. Jak wspomniano wcześniej, moim celem w tym artykule jest dostarczenie wystarczającej ilości krytycznego tła teoretycznego, aby wyjaśnić zamieszanie wokół wyrażeń tabel, zanim zacznę zagłębiać się w szczegóły dotyczące T-SQL w przyszłych artykułach.
Co to jest wyrażenie tabeli?
Algebra relacyjna (algebra definiująca operacje na relacjach w teorii relacji) ma zamknięcie własność. Oznacza to, że operacja na relacjach daje relację. Operator relacji działa na jednej lub kilku relacjach jako danych wejściowych i zwraca pojedynczą relację jako dane wyjściowe. Właściwość closure umożliwia zagnieżdżanie operacji. wyrażenie relacyjne to wyrażenie, które operuje na relacjach i zwraca relację. Wyrażenie relacyjne może być zatem użyte tam, gdzie algebra relacyjna oczekuje relacji.
Jeśli się nad tym zastanowisz, nie różni się to niczym od operacji na liczbach całkowitych, które dają wynik całkowity. Załóżmy, że zmienna @i jest zmienną całkowitą. Wyrażenie @i + 42 daje liczbę całkowitą i dlatego może być używane tam, gdzie oczekiwana jest liczba całkowita, jak w (@i + 42) * 2.
Biorąc pod uwagę, że tabela w SQL jest odpowiednikiem relacji w teorii relacyjnej, choć nie jest to bardzo udana, wyrażenie tabelowe w SQL jest odpowiednikiem wyrażenia relacyjnego. Jak wspomniano wcześniej, używam terminu wyrażenie tabelowe po użyciu tego terminu przez C.J. Dates. Standard SQL zawiera mnóstwo mylących terminów, z których niektóre, jak sądzę, nie są zbyt odpowiednie. Na przykład standard SQL używa terminu wyrażenie tabelowe do opisania wyrażenia opartego na klauzulach zapytania rozpoczynających się obowiązkową klauzulą FROM i opcjonalnie zawierających klauzule WHERE, GROUP BY, HAVING i WINDOW (ostatnia nie jest obsługiwana w T -SQL) i wyłączając klauzulę SELECT. Oto specyfikacja standardu:
7.4
Funkcja
Określ tabelę lub tabelę zgrupowaną.
Format
Prawdą jest, że wynik tego, co norma nazywa wyrażeniem tabelowym, jest uważany za tabelę, ale nie można używać takiego wyrażenia jako samodzielnego zapytania. Wersja wyrażenia tabelowego z datą jest w rzeczywistości bliższa temu, co standard SQL nazywa wyrażeniem zapytania . Oto specyfikacja standardu dotycząca tego, co nazywa wyrażenie zapytania:
7.17
Funkcja
Format
7.3
Funkcja
Format
Zauważ, że ta specyfikacja zawiera to, co T-SQL nazywa typowym wyrażeniem tabelowym, mimo że standard tak naprawdę nie używa tego terminu, a jedynie nazywa go z elementem listy . Zauważ również, że tak zwane wyrażenie zapytania nie musi być oparte na zapytaniu, a raczej może być oparte na tak zwanym konstruktorze wartości tabeli (użycie klauzuli VALUES do skonstruowania zestawu wierszy). Wreszcie, mimo że standardowe wyrażenie zapytania jest oparte na wyrażeniu, zwraca ono tabelę i może być używane tam, gdzie zwykle oczekuje się tabeli. Z tych powodów uważam, że użycie przez Date terminu wyrażenie tabelowe jest o wiele bardziej odpowiednie.
Rozumiem, dlaczego niektórzy mogą uważać rozpamiętywanie nazewnictwa i terminologii za nieco pedantyczne, a może nawet za stratę czasu. Jednak czuję się zupełnie inaczej. Uważam, że w każdej dziedzinie dążenie do używania nazw własnych i terminologii zmusza do dobrego przestudiowania podstaw i refleksji nad posiadaną wiedzą. Mając nadzieję, że w tym artykule nie udało mi się Was na tyle zrazić, by nie chcieć przechodzić do kolejnych części serii, począwszy od artykułu z przyszłego miesiąca, skupię się na sposobie, w jaki różne rodzaje nazwanych wyrażenia tabelowe są obsługiwane przy użyciu T-SQL w SQL Server i Azure SQL Database.
[
[
[
[
Określ tabelę.
[
[
Z [ REKURSIVE ]
AS
|
[
|
[
|
[
|
[
|
|
TABLE
CORRESPONDING [ BY
ORDER BY
PRZESUNIĘCIE
FETCH { FIRST | NEXT } [
|
Określ zestaw
VALUES
WARTOŚCI
[ { Wniosek