Denne artikel er den første i en serie om det grundlæggende i tabeludtryk i T-SQL. Jeg vil hovedsageligt fokusere på fire typer af navngivne tabeludtryk, som i T-SQL er kendt som afledte tabeller, almindelige tabeludtryk (CTE'er), visninger og inline-tabelværdierede funktioner (inline TVF'er).
Jeg blev inspireret til at skrive denne serie af min gode ven, Grant Fritchey, som jeg har kendt i mange år. Som Grant gentagne gange påpeger, tror mange, der bruger almindelige tabeludtryk i T-SQL, at SQL Server bevarer det indre forespørgselsresultatsæt, og at årsagen til denne tro er brugen af udtrykket tabel i konstruktionens navn. Når dette emne kommer op i samfundsdiskussioner, hævder folk ofte, at brugen af udtrykket tabel i konstruktionens navn er upassende, da det ikke rigtig er en tabel. Der er endda forslag til at starte en navnekampagne i håb om at se en fremtidig navneændring for denne konstruktion, i det mindste i T-SQL. Nogle af forslagene inkluderer forespørgselsudtryk , indbygget visning , visning på erklæringsniveau , og andre.
Måske vil dette komme som en overraskelse for nogle, men jeg finder faktisk brugen af udtrykket tabel i almindeligt tabeludtryk som meget passende. Faktisk finder jeg brugen af udtrykket tabeludtryk som passende. For mig er den bedste måde at beskrive, hvad en CTE er i T-SQL, det er et navngivet tabeludtryk . Det samme gælder hvad T-SQL kalder afledte tabeller (den specifikke sprogkonstruktion i modsætning til den generelle idé), synspunkter og inline TVF'er. De er alle navngivne tabeludtryk.
Hvis du kan tåle mig lidt, vil jeg give begrundelsen for mit syn på tingene i denne artikel. Det gik op for mig, at både navneforvirringen og forvirringen omkring, hvorvidt der er et persistens-aspekt ved tabeludtryk, kan fjernes med en bedre forståelse af det grundlæggende i vores felt af relationelle databasestyringssystemer. Disse grundlæggende elementer er relationsteori, hvordan SQL (standardsproget) relaterer til det, og hvordan T-SQL-dialekten, der bruges i SQL Server og Azure SQL Database-implementeringerne, relaterer til begge dele.
Som udgangspunkt ønsker du at kunne svare på følgende spørgsmål:
- Hvad betyder den fysiske datauafhængighed princip i relationsmodellen betyder?
- Hvad er en tabel i SQL, og hvad er modstykket i relationsmodellen?
- Hvad er lukningsegenskaben for relationel algebra?
- Hvad er et tabeludtryk, og hvad er modstykket i relationsmodellen?
Når du er i stand til at besvare ovenstående spørgsmål korrekt, vil du højst sandsynligt finde brugen af udtrykket navngivet tabeludtryk som passende for de førnævnte konstruktioner (det T-SQL kalder afledte tabeller, CTE'er, visninger og inline TVF'er).
Jeg vil ikke lyde, som om jeg har en meget dyb forståelse af relationsteori. Min ekspertise er T-SQL. Jeg anerkender, at der er meget mere, jeg ikke ved om relationsteori, end jeg gør, og at nogle ting, som jeg tror, jeg ved, bare ikke er det. Når jeg læser C. J. Dates' skrifter om emnet, føler jeg, at jeg knap skraber i overfladen af, hvad der er at vide, og at jeg kunne og burde stræbe efter at forstå det bedre. Jeg anerkender og tror fuldt og fast på, at en god forståelse af relationsteori oversættes direkte til en bedre forståelse af SQL og T-SQL og til at skrive bedre, mere præcis og mere robust T-SQL-kode. For alle, der vælger data som deres karriere, anbefaler jeg at læse SQL and Relational Theory:How to Write Accurate SQL Code 3rd Edition af C. J. Date (O'Reilly 2015).
I den første del af denne serie ønsker jeg at etablere en forståelse af min brug af begreberne tabeludtryk og navngivet tabeludtryk , hvilket er i overensstemmelse med Dates brug af dette udtryk, og desværre ikke i overensstemmelse med SQL Standardens brug af dette udtryk. For at opnå dette vil jeg give lidt baggrund fra relationsteori og SQL-standarden. Men som sagt, jeg anbefaler at læse Dates bog for en virkelig detaljeret dækning af dette emne.
Jeg vil starte med at forklare, hvad princippet om fysisk datauafhængighed betyder. Dernæst vil jeg forklare, hvad en tabel er i SQL og dens modstykke i relationsteori. Jeg vil derefter forklare, hvad lukningsegenskaben ved relationel algebra betyder. Når du først har en rimelig idé om, hvad et bord er, og hvad lukkeegenskaben betyder, bliver det ret ligetil at forstå, hvad et tabeludtryk er. Mit fokus vil derefter vende sig til detaljerne i T-SQL. Jeg har meget at sige om det grundlæggende i tabeludtryk i T-SQL – både med hensyn til den konceptuelle behandling og med hensyn til implementeringsdetaljerne, inklusive overvejelser om fysisk repræsentation og forespørgselsjustering.
Jeg finder dette emne fascinerende og meget praktisk, når du først dykker ned i implementeringsdetaljerne. Faktisk har jeg så meget at sige om det, at jeg ikke er sikker på, hvor mange dele denne serie i sidste ende vil indeholde. Hvad jeg kan fortælle dig med stor grad af selvtillid er, at der vil være flere dele. Sandsynligvis mere end én og færre end 100. I fremtidige dele vil jeg dykke ned i de enkelte typer af navngivne tabeludtryk, modifikationsovervejelser, inlining-aspekter, rækkefølgeaspekter, korrelationer og mere.
I mine eksempler vil jeg bruge en prøvedatabase kaldet TSQLV5. Du kan finde scriptet, der opretter og udfylder denne database her, og dets ER-diagram her.
Uafhængighed af fysiske data
Fysisk datauafhængighed er et princip i relationsteorien, der siger, at de fysiske implementeringsdetaljer skal være skjult for eller gennemsigtige for brugeren, der sender forespørgslerne mod relationsdatabasestyringssystemet. I forespørgslerne skal brugerne fokusere på hvad de skal bruge logiske operationer, der er baseret på relationel algebra, i modsætning til hvordan for at få dataene. Det er ikke meningen, at de skal bekymre sig om, hvordan data er struktureret, tilgået og behandlet. Sådanne fysiske implementeringsdetaljer har en tendens til at adskille sig væsentligt mellem forskellige implementeringer (RDBMS-produkter). Selv med det samme RDBMS ændres de fysiske implementeringsdetaljer nogle gange mellem forskellige versioner og builds. Ideen bag princippet om fysisk datauafhængighed er i teorien at beskytte brugerinvesteringen ved at fjerne behovet for at revidere dine løsninger, når du opgraderer dit RDBMS til en ny version, eller endda når du migrerer fra et RDBMS til et andet. Som du sikkert godt ved, er tingene i praksis ikke så enkle, men det er et emne for en anden diskussion.
Hvad er en tabel?
Hvis du har arbejdet med T-SQL eller en anden dialekt af SQL i et stykke tid, udvikler du en intuitiv forståelse af, hvad en tabel er. Problemet er, at uden en vis baggrund for relationel teori, er den intuitive forståelse ofte ikke særlig præcis. En typisk fejl er, at vi intuitivt har en tendens til at fokusere på fysiske implementeringsdetaljer. For eksempel, når du tænker på, hvad en tabel er, tænker du på en tabel som en logisk struktur (et sæt rækker) eller tænker du på fysiske implementeringsdetaljer i den platform, du bruger (i SQL Server , sider, omfang, heap versus klynget indeks, ikke-klyngede indekser og så videre)? Som bruger, der skriver SQL-kode for at forespørge en tabel, efter princippet om fysisk datauafhængighed, er det meningen, at du skal tænke på tabellen som en logisk struktur og lade RDBMS bekymre sig om de fysiske implementeringsdetaljer. Så lad os tage et skridt tilbage og prøve at finde ud af, hvad et bord er.
En tabel er SQLs modstykke til hovedstrukturen i relationsteori - en relation. For at holde tingene enkle og begrænse omfanget af min dækning, vil jeg ikke gå ind i sondringen mellem en relationsvariabel og en relationsværdi. Hvis du følger min anbefaling og læser Dates bog, vil du meget hurtigt få et klart billede af sådanne finesser.
En relation har en overskrift og en krop.
Relationens overskrift er et sæt af attributter . I matematisk mængdelære har en mængde ingen rækkefølge og ingen dubletter. Du skal identificere en egenskab ved navn og ikke ved en position. Derfor skal attributnavne være unikke.
Kan du identificere, hvad der er modstykket til en attribut i SQL? Du har sikkert gættet, at det er en kolonne . Men SQL har faktisk en forestilling om rækkefølge til sine kolonner baseret på deres rækkefølge i CREATE TABLE-sætningen. Her er f.eks. CREATE TABLE-erklæringen for tabellen Sales.Shippers i TSQLV5-databasen:
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) );
Forespørg tabellen ved hjælp af den berygtede SELECT *
, sådan:
SELECT * FROM Sales.Shippers;
Da jeg kørte denne forespørgsel i mit system, fik jeg følgende output:
shipperid companyname phone ---------- -------------- --------------- 1 Shipper GVSUA (503) 555-0137 2 Shipper ETYNR (425) 555-0136 3 Shipper ZHISN (415) 555-0138
SQL garanterer, at kolonnerne returneres fra venstre mod højre baseret på definitionsrækkefølge. Jeg vil snart forklare, hvad der sker med rækkerne. SQL giver dig endda mulighed for at henvise til rækkefølgen af kolonnen fra SELECT-listen i ORDER BY-sætningen, sådan set (ikke at jeg anbefaler denne praksis, og det gør Aaron Bertrand heller ikke):
SELECT shipperid, companyname, phone FROM Sales.Shippers ORDER BY 2;
Denne forespørgsel genererer følgende output:
shipperid companyname phone ---------- -------------- --------------- 2 Shipper ETYNR (425) 555-0136 1 Shipper GVSUA (503) 555-0137 3 Shipper ZHISN (415) 555-0138
Brødteksten i en relation er et sæt tupler . Husk igen, at et sæt ikke har nogen rækkefølge og ingen dubletter. Derfor skal en relation have mindst én kandidatnøgle, der giver dig mulighed for entydigt at identificere en tupel. SQLs modstykke til en tuple er en række . Men i SQL er du ikke tvunget til at definere en nøgle i en tabel, og hvis du ikke gør det, kan du ende med duplikerede rækker. Selvom du har en nøgle defineret i din tabel, kan du få duplikerede rækker returneret fra en forespørgsel mod tabellen. Her er et eksempel:
SELECT country FROM HR.Employees;
Denne forespørgsel genererer følgende output:
country -------- USA USA USA USA UK UK UK USA UK
Denne forespørgsel producerer ikke et relationelt resultat på grund af muligheden for duplikerede rækker. Mens relationsteori er baseret på mængdeteori, er SQL baseret på multisætteori. Et multisæt (alias et supersæt eller en taske) kan have dubletter. SQL giver dig et værktøj til at eliminere dubletter med en DISTINCT-sætning, som sådan:
SELECT DISTINCT country FROM HR.Employees;
Denne forespørgsel genererer følgende output:
country -------- UK USA
Hvad SQL vedligeholder fra relationsteori med hensyn til tabellens krop, er egenskaben uden orden. Medmindre du tilføjer en ORDER BY-klausul i forespørgslen, har du ingen forsikringer om, at resultatet vil have nogen specifik rækkefølge blandt rækkerne. Så brødteksten i ovenstående forespørgselsresultat er relationel, i det mindste i den forstand, at den ikke har dubletter, og den ikke har garanteret rækkefølge.
Antag, at du forespørger i en tabel i SQL Server, og at du ikke inkluderer en ORDER BY-klausul i forespørgslen. Forventer du, at SQL Server altid returnerer rækkerne i en bestemt rækkefølge som en garanteret adfærd? Mange mennesker gør. Mange tror, at du altid vil få rækkerne tilbage baseret på klynget indeksrækkefølge. Det er et godt eksempel på at ignorere princippet om fysisk datauafhængighed og gøre antagelser baseret på intuition og måske baseret på tidligere observeret adfærd. Microsoft ved, at en SQL-forespørgsel uden en ORDER BY-klausul ikke garanterer nogen rækkefølge blandt resultatrækkerne, og selv om dataene på det fysiske niveau ligger i en indeksstruktur, behøver SQL Server ikke at behandle dataene i indekset. bestille. Det kan vælge, under visse fysiske forhold, at gøre det, men det kan vælge at lade være under andre fysiske forhold. Husk også, at de fysiske implementeringsdetaljer kan ændre sig mellem forskellige versioner og builds af produktet. Hvis du vil garantere, at forespørgslen returnerer resultatrækkerne i en bestemt rækkefølge, er din eneste måde at garantere dette på at indføre en ORDER BY-klausul i den yderste forespørgsel.
Som du sikkert har forstået, så udviklerne af SQL det ikke rigtig som en prioritet at følge relationsteori. Og det, jeg beskrev her, er blot nogle få eksempler. Der er mange flere. Som nævnt tidligere, er mit mål i denne artikel blot at give nok af den kritiske teoretiske baggrund til at fjerne forvirringen omkring tabeludtryk, før jeg begynder at dykke ned i detaljerne i T-SQL i fremtidige artikler.
Hvad er et tabeludtryk?
Relationel algebra (algebraen, der definerer operationer på relationer i relationsteori) har en lukning ejendom. Hvad det betyder er, at en operation på relationer giver en relation. En relationel operator opererer på en eller flere relationer som input og giver en enkelt relation som output. Lukningsegenskaben giver dig mulighed for at indlejre operationer. Et relationelt udtryk er et udtryk, der opererer på relationer og returnerer en relation. Et relationelt udtryk kan derfor bruges, hvor relationel algebra forventer en relation.
Hvis du tænker over det, er det ikke anderledes end operationer på heltal, der giver et heltalsresultat. Antag, at variablen @i er en heltalsvariabel. Udtrykket @i + 42 giver et heltal og kan derfor bruges, hvor der forventes et heltal, som i (@i + 42) * 2.
I betragtning af at en tabel i SQL er modstykket til en relation i relationsteori, omend ikke en særlig vellykket sådan, er et tabeludtryk i SQL modstykket til et relationelt udtryk. Som nævnt tidligere bruger jeg termen tabeludtryk efter C. J. Dates' brug af dette udtryk. SQL-standarden har en række forvirrende udtryk, hvoraf nogle jeg er bange for ikke er særlig passende. SQL-standarden bruger f.eks. termen tabeludtryk til specifikt at beskrive et udtryk baseret på forespørgselssætningerne, der starter med en obligatorisk FROM-klausul, og inkluderer valgfrit sætningerne WHERE, GROUP BY, HAVING og WINDOW (det sidste er ikke understøttet i T -SQL), og ekskluderer SELECT-sætningen. Her er standardens specifikation:
7.4
Funktion
Angiv en tabel eller en grupperet tabel.
Format
Det er rigtigt, at resultatet af det, som standarden kalder et tabeludtryk, betragtes som en tabel, men du kan ikke bruge et sådant udtryk som en selvstændig forespørgsel. Dates version af termen tabeludtryk er faktisk tættere på det, SQL-standarden kalder forespørgselsudtryk . Her er standardens specifikation for det, den kalder forespørgselsudtryk:
7.17
Funktion
Format
7.3
Funktion
Format
Bemærk, at denne specifikation inkluderer, hvad T-SQL kalder fælles tabeludtryk, selvom standarden ikke rigtig bruger dette udtryk, men blot kalder det med listeelement . Bemærk også, at det såkaldte forespørgselsudtryk ikke behøver at være baseret på en forespørgsel, men snarere kan være baseret på det, der kaldes en tabelværdikonstruktør (brugen af en VALUES-sætning til at konstruere et sæt rækker). Til sidst, selvom standardens forespørgselsudtryk er baseret på et udtryk, returnerer det en tabel og kan bruges, hvor en tabel normalt forventes. Af disse grunde finder jeg Dates brug af termen tabeludtryk meget mere passende.
Jeg kan se, hvorfor nogle måske synes, at dvælen ved navngivning og terminologi er lidt pedantisk og måske endda spild af tid. Jeg har det dog meget anderledes. Jeg tror på, at et ønske om at bruge egennavne og terminologi på ethvert område tvinger dig til at studere grundlaget godt og reflekterer over din viden. I håb om, at jeg ikke i denne artikel formåede at fremmedgøre dig nok til ikke at ville fortsætte til de kommende dele i serien, begyndende med næste måneds artikel, vil jeg vende mit fokus til den måde, de forskellige typer navngivne tabeludtryk håndteres ved hjælp af T-SQL i SQL Server og Azure SQL Database.
[
[
[
[
Angiv en tabel.
[
[
MED [ REKURSIV ]
AS ]
|
[
|
[
|
[
|
[
|
|
TABEL
TILSVARENDE [ AF
ORDER BY
OFFSET
FETCH { FIRST | NÆSTE } [
|
Angiv et sæt
VÆRDIER
VALUES
[ { Konklusion