sql >> Databasteknik >  >> RDS >> Database

Grunderna för tabelluttryck, del 1

Den här artikeln är den första i en serie om grunderna för tabelluttryck i T-SQL. Jag kommer huvudsakligen att fokusera på fyra typer av namngivna tabelluttryck, som i T-SQL är kända som härledda tabeller, vanliga tabelluttryck (CTE), vyer och inline-tabellvärderade funktioner (inline TVF).

Jag blev inspirerad att skriva den här serien av min gode vän, Grant Fritchey, som jag har känt i många år. Som Grant upprepade gånger påpekar tror många som använder vanliga tabelluttryck i T-SQL att SQL Server behåller den inre frågeresultatuppsättningen och att anledningen till denna övertygelse är användningen av termen tabell i konstruktionens namn. När det här ämnet kommer upp i samhällsdiskussioner hävdar folk ofta att användningen av termen tabell i konstruktionens namn är olämplig eftersom det egentligen inte är en tabell. Det finns till och med förslag på att starta en namnkampanj i hopp om att se ett framtida namnbyte för denna konstruktion, åtminstone i T-SQL. Några av förslagen inkluderar frågeuttryck , inlinevy , vy på uttalandenivå , och andra.

Kanske kommer detta som en överraskning för vissa, men jag tycker faktiskt att termen tabell används i vanligt tabelluttryck som mycket lämpligt. Jag tycker faktiskt att termen tabelluttryck används som lämpligt. För mig är det bästa sättet att beskriva vad en CTE är i T-SQL, det är ett namngivet tabelluttryck . Detsamma gäller vad T-SQL kallar härledda tabeller (den specifika språkkonstruktionen i motsats till den allmänna idén), vyer och inline TVF. De är alla namngivna tabelluttryck.

Om du orkar med mig lite, kommer jag att motivera min syn på saker och ting i den här artikeln. Det slog mig att både namnförvirringen och förvirringen kring huruvida det finns en persistensaspekt i tabelluttryck, kan rensas med en bättre förståelse av grunderna i vårt område för relationsdatabashanteringssystem. Grunderna är relationsteori, hur SQL (standardspråket) relaterar till det och hur T-SQL-dialekten som används i SQL Server- och Azure SQL Database-implementeringarna relaterar till båda.

Som utgångspunkt vill du kunna svara på följande frågor:

  • Vad innebär fysisk dataoberoende princip i relationsmodellen betyder?
  • Vad är en tabell i SQL och vad är motsvarigheten i relationsmodellen?
  • Vad är closure-egenskapen för relationalgebra?
  • Vad är ett tabelluttryck och vad är motsvarigheten i relationsmodellen?

När du väl kan besvara frågorna ovan korrekt, kommer du med stor sannolikhet att hitta användningen av termen named table expression som är lämpligt för de ovan nämnda konstruktionerna (det som T-SQL kallar härledda tabeller, CTE:er, vyer och inline TVFs).

Jag vill inte låta som att jag har en mycket djup förståelse för relationsteori. Min expertis är T-SQL. Jag erkänner att det finns mycket mer som jag inte vet om relationsteori än vad jag gör, och att vissa saker som jag tror att jag vet inte är så. När jag läser C. J. Dates skrifter om ämnet känner jag att jag knappt skrapar på ytan av vad som finns att veta, och att jag kunde och borde sträva efter att förstå det bättre. Jag är medveten om och är övertygad om att en god förståelse av relationsteori leder direkt till en bättre förståelse av SQL och T-SQL, och till att skriva bättre, mer exakt och mer robust T-SQL-kod. För alla som väljer data som sin karriär rekommenderar jag att läsa SQL and Relational Theory:How to Write Accurate SQL Code 3rd Edition av C. J. Date (O'Reilly 2015).

I den första delen av denna serie vill jag skapa en förståelse för min användning av termerna tabelluttryck och namngivet tabelluttryck , vilket är i överensstämmelse med Dates användning av denna term, och tyvärr inte i överensstämmelse med SQL Standards användning av denna term. För att uppnå detta kommer jag att ge lite bakgrund från relationsteori och SQL-standarden. Men som jag sa, jag rekommenderar att du läser Dates bok för en verkligt detaljerad täckning av detta ämne.

Jag börjar med att förklara vad principen om fysisk dataoberoende betyder. Därefter kommer jag att förklara vad en tabell är i SQL och dess motsvarighet i relationsteori. Jag ska sedan förklara vad stängningsegenskapen för relationalgebra betyder. När du väl har en rimlig uppfattning om vad en tabell är och vad stängningsegenskapen betyder, blir det ganska enkelt att förstå vad ett tabelluttryck är. Mitt fokus kommer då att övergå till detaljerna i T-SQL. Jag har mycket att säga om grunderna för tabelluttryck i T-SQL – både när det gäller den konceptuella behandlingen och när det gäller implementeringsdetaljerna, inklusive fysisk representation och frågejustering.

Jag tycker att det här ämnet är fascinerande och väldigt praktiskt när du väl har fördjupat dig i implementeringsdetaljerna. Faktum är att jag har så mycket att säga om det att jag inte är säker på hur många delar den här serien så småningom kommer att innehålla. Vad jag kan berätta för dig med en stor grad av tillförsikt är att det kommer att finnas flera delar. Förmodligen fler än en och färre än 100. I kommande delar kommer jag att fördjupa mig i de individuella typerna av namngivna tabelluttryck, modifieringsöverväganden, inlinningsaspekter, ordningsaspekter, korrelationer och mer.

I mina exempel kommer jag att använda en exempeldatabas som heter TSQLV5. Du kan hitta skriptet som skapar och fyller denna databas här, och dess ER-diagram här.

Oberoende av fysisk data

Fysiskt dataoberoende är en princip inom relationsteorin som säger att de fysiska implementeringsdetaljerna ska vara dolda från, eller transparenta för, användaren som skickar frågorna mot relationsdatabasens hanteringssystem. I frågorna ska användarna fokusera på vad de behöver använda logiska operationer som är baserade på relationalgebra, i motsats till hur för att få uppgifterna. De ska inte oroa sig för hur data struktureras, nås och bearbetas. Sådana fysiska implementeringsdetaljer tenderar att skilja sig väsentligt mellan olika implementeringar (RDBMS-produkter). Även med samma RDBMS ändras de fysiska implementeringsdetaljerna ibland mellan olika versioner och builds. Tanken bakom principen om fysisk dataoberoende i teorin är att skydda användarinvesteringen genom att ta bort behovet av att revidera dina lösningar när du uppgraderar ditt RDBMS till en ny version, eller till och med när du migrerar från ett RDBMS till ett annat. Som du säkert vet är saker och ting inte så enkla i praktiken, men det är ett ämne för en annan diskussion.

Vad är ett bord?

Om du har arbetat med T-SQL eller någon annan dialekt av SQL ett tag, utvecklar du en intuitiv förståelse för vad en tabell är. Problemet är att utan någon bakgrund av relationsteori är ofta den intuitiva förståelsen inte särskilt korrekt. Ett typiskt misstag är att vi intuitivt tenderar att fokusera på fysiska implementeringsdetaljer. Till exempel, när du tänker på vad en tabell är, tänker du på en tabell som en logisk struktur (en uppsättning rader) eller tänker du på fysiska implementeringsdetaljer i plattformen som du använder (i SQL Server , sidor, omfattningar, heap kontra klustrade index, icke-klustrade index och så vidare)? Som användare som skriver SQL-kod för att fråga en tabell, enligt principen om fysisk dataoberoende, är det meningen att du ska tänka på tabellen som en logisk struktur och låta RDBMS oroa sig för de fysiska implementeringsdetaljerna. Så låt oss ta ett steg tillbaka och försöka ta reda på vad ett bord är.

En tabell är SQLs motsvarighet till huvudstrukturen i relationsteori - en relation. För att göra saker enkelt och begränsa omfattningen av min täckning, tänker jag inte gå in på skillnaden mellan en relationsvariabel och ett relationsvärde. Om du följer min rekommendation och läser Dates bok kommer du mycket snabbt att få en tydlig bild av sådana finesser.

En relation har en rubrik och en kropp.

Rubriken för relationen är en uppsättning av attribut . I matematisk mängdlära har en mängd ingen ordning och inga dubbletter. Du ska identifiera ett attribut med namn och inte med någon position. Följaktligen måste attributnamnen vara unika.

Kan du identifiera vad som är motsvarigheten till ett attribut i SQL? Du har förmodligen gissat att det är en kolumn . Men SQL har faktiskt en uppfattning om ordning på sina kolumner baserat på deras ordningsföljd i CREATE TABLE-satsen. Till exempel, här är CREATE TABLE-satsen för 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)
);

Fråga tabellen med den ökända SELECT * , som så:

SELECT * FROM Sales.Shippers;

När jag körde den här frågan i mitt system fick jag följande utdata:

shipperid  companyname    phone
---------- -------------- ---------------
1          Shipper GVSUA  (503) 555-0137
2          Shipper ETYNR  (425) 555-0136
3          Shipper ZHISN  (415) 555-0138

SQL garanterar att kolumnerna kommer att returneras från vänster till höger baserat på definitionsordning. Jag ska snart förklara vad som händer med raderna. SQL tillåter dig till och med att referera till kolumnens ordningsposition från SELECT-listan i ORDER BY-satsen, som så (inte för att jag rekommenderar denna praxis, inte heller Aaron Bertrand):

SELECT shipperid, companyname, phone
FROM Sales.Shippers
ORDER BY 2;

Den här frågan genererar följande utdata:

shipperid  companyname    phone
---------- -------------- ---------------
2          Shipper ETYNR  (425) 555-0136
1          Shipper GVSUA  (503) 555-0137
3          Shipper ZHISN  (415) 555-0138

Brödtexten i en relation är en uppsättning tupler . Återigen, kom ihåg att en uppsättning inte har någon ordning och inga dubbletter. Därför måste en relation ha minst en kandidatnyckel som låter dig identifiera en tupel unikt. SQLs motsvarighet till en tuppel är en rad . Men i SQL är du inte tvungen att definiera en nyckel i en tabell, och om du inte gör det kan du sluta med dubbletter av rader. Även om du har en nyckel definierad i din tabell, kan du få dubbletter av rader returnerade från en fråga mot tabellen. Här är ett exempel:

SELECT country FROM HR.Employees;

Den här frågan genererar följande utdata:

country
--------
USA
USA
USA
USA
UK
UK
UK
USA
UK

Den här frågan ger inget relationsresultat på grund av möjligheten till dubbletter av rader. Medan relationsteori är baserad på mängdteori, baseras SQL på multisetteori. En multiset (aka en superset eller en väska) kan ha dubbletter. SQL ger dig ett verktyg för att eliminera dubbletter med en DISTINCT-sats, som så:

SELECT DISTINCT country FROM HR.Employees;

Den här frågan genererar följande utdata:

country
--------
UK
USA

Vad SQL upprätthåller från relationsteori när det gäller tabellens kropp är egenskapen no-order. Om du inte lägger till en ORDER BY-sats i frågan, har du inga garantier för att resultatet kommer att ha någon specifik ordning bland raderna. Så brödtexten i ovanstående frågeresultat är relationell, åtminstone i den meningen att den inte har dubbletter och inte har garanterad ordning.

Anta att du frågar en tabell i SQL Server och att du inte inkluderar en ORDER BY-sats i frågan. Förväntar du dig att SQL Server alltid ska returnera raderna i någon specifik ordning som ett garanterat beteende? Många människor gör det. Många tror att du alltid kommer att få tillbaka raderna baserat på klustrad indexordning. Det är ett bra exempel på att ignorera principen om fysisk dataoberoende och göra antaganden baserade på intuition, och kanske baserade på tidigare observerat beteende. Microsoft vet att en SQL-fråga utan en ORDER BY-klausul inte garanterar någon ordning bland resultatraderna, och även om data på den fysiska nivån finns i en indexstruktur, behöver SQL Server inte bearbeta data i index beställa. Den kan välja, under vissa fysiska förhållanden, att göra det, men den kan välja att inte göra det under andra fysiska förhållanden. Kom också ihåg att de fysiska implementeringsdetaljerna kan ändras mellan olika versioner och konstruktioner av produkten. Om du vill garantera att frågan kommer att returnera resultatraderna i någon specifik ordning, är ditt enda sätt att garantera detta att införa en ORDER BY-sats i den yttersta frågan.

Som du säkert har förstått, såg designerna av SQL det inte riktigt som en prioritet att följa relationsteori. Och det jag beskrev här är bara några exempel. Det finns många fler. Som nämnts tidigare är mitt mål i den här artikeln bara att ge tillräckligt med den kritiska teoretiska bakgrunden för att rensa förvirringen kring tabelluttryck, innan jag börjar fördjupa mig i detaljerna i T-SQL i framtida artiklar.

Vad är ett tabelluttryck?

Relationell algebra (algebra som definierar operationer på relationer i relationsteori) har en stängning fast egendom. Vad det betyder är att en operation på relationer ger en relation. En relationsoperator arbetar på en eller flera relationer som input och ger en enda relation som utdata. Stängningsegenskapen låter dig kapsla operationer. Ett relationsuttryck är ett uttryck som verkar på relationer och returnerar en relation. Ett relationsuttryck kan därför användas där relationalgebra förväntar sig en relation.

Om du tänker på det är det inte annorlunda än operationer på heltal som ger ett heltalsresultat. Antag att variabeln @i är en heltalsvariabel. Uttrycket @i + 42 ger ett heltal och kan därför användas där ett heltal förväntas, som i (@i + 42) * 2.

Med tanke på att en tabell i SQL är motsvarigheten till en relation i relationsteori, om än inte särskilt framgångsrik, är ett tabelluttryck i SQL motsvarigheten till ett relationsuttryck. Som nämnts tidigare använder jag termen tabelluttryck efter C. J. Dates användning av denna term. SQL-standarden har en mängd förvirrande termer, av vilka jag är rädd att några inte är särskilt lämpliga. Till exempel använder SQL-standarden termen tabelluttryck för att specifikt beskriva ett uttryck baserat på frågesatserna som börjar med en obligatorisk FROM-sats, och inkluderar valfritt satserna WHERE, GROUP BY, HAVING och WINDOW (den sista stöds inte i T -SQL), och exklusive SELECT-satsen. Här är standardens specifikation:

7.4

Funktion
Ange en tabell eller en grupperad tabell.

Format
::=

[ ]
[ ]
[ ]
[ ]

Det är sant att resultatet av det som standarden kallar ett tabelluttryck anses vara en tabell, men du kan inte använda ett sådant uttryck som en fristående fråga. Dates version av termen tabelluttryck är faktiskt närmare vad SQL-standarden kallar frågeuttryck . Här är standardens specifikation för vad den kallar frågeuttryck:

7.17

Funktion
Ange en tabell.

Format
::=
[ ]
[ ] [ ] [ ]
::=
MED [ REKURSIV ]
::=
[ { }… ]
::=
[ ]
AS [ ]
::=

::=

| UNION [ ALLA | DISTINCT ]
[ ]
| EXCEPT [ALLA | DISTINCT ]
[ ]
::=

| INTERSECT [ ALLA | DISTINCT ]
[ ]
::=

|
[ ] [ ] [ ]

::=

|
|
::=
TABELL
::=
SAMMANDRAG [ AV kolumnlista> ]
::=

::=
ORDER BY
::=
OFFSET { ROW | RADER
::=
HÄMTA { FÖRSTA | NÄSTA } [ ] { RAD | RADER } { ENDAST | MED SLIPS
::=

|
::=

::=

::=
PROCENT

7.3

Funktion
Ange en uppsättning s som ska konstrueras till en tabell.

Format
::=
VÄRDEN
::=
[ { }… ]
::=
VÄRDEN
::=

[ { }… ]

Observera att den här specifikationen inkluderar vad T-SQL kallar vanligt tabelluttryck, även om standarden inte riktigt använder denna term, utan bara kallar den med listelement . Observera också att det så kallade frågeuttrycket inte behöver baseras på en fråga, utan snarare kan baseras på vad som kallas en tabellvärdekonstruktor (användningen av en VALUES-sats för att konstruera en uppsättning rader). Slutligen, även om standardens frågeuttryck är baserat på ett uttryck, returnerar det en tabell och kan användas där en tabell normalt förväntas. Av dessa skäl tycker jag att Dates användning av termen tabelluttryck är mycket mer lämplig.

Slutsats

Jag kan se varför vissa kanske tycker att uppehållet vid namngivning och terminologi är lite pedantisk och kanske till och med slöseri med tid. Men jag känner mig väldigt annorlunda. Jag tror att en strävan att använda egennamn och terminologi inom vilket område som helst tvingar dig att studera grunderna väl och reflekterar över dina kunskaper. I hopp om att jag i den här artikeln inte lyckades alienera dig tillräckligt för att inte vilja fortsätta till de kommande delarna i serien, med början med nästa månads artikel, tänker jag vända mitt fokus till hur de olika typerna av namn Tabelluttryck hanteras med T-SQL i SQL Server och Azure SQL Database.


  1. MySQL PI() Funktion – Returnera värdet av π (pi)

  2. Så skapar du ett tomt formulär i Access 2016

  3. Vilket är det enklaste sättet att fylla på tomma datum i SQL-resultat (antingen i mysql- eller perl-änden)?

  4. SQLAlchemy deklarativ:definiera utlösare och index (Postgres 9)