SELECT i detaljer samt opsamlingsfunktioner

Tags:    databaser
<< < 123 > >>
Skrevet af Bruger #4522 @ 06.02.2008

Mængdefunktioner


SUM
I 1911 går den engelske konge rundt og planlægger en fejring. Han vil fejre alle sine skibe der er til stede i London sammen med et Chilensk og et Japansk skib (tilfældigvis dem som står i Ships-tabellen). Han planlægger at få alle skibene til at lægge anker ved den kongelige kaj, så folk kan besøge skibene. Der er kun ét problem. Er kajen lang nok til at alle skiben kan lægge til? Kongen, som er lidt forud for sin tid, får den idé at han da kan bruge mængdefunktionen SUM. Glad og fro går han ind i sine kongelige gemakker og sender følgende SQL til sin SQL Server 2005 Royal Edition (ok., han er meget forud for sin tid):

Fold kodeboks ind/udKode 


Resultater er:

Fold kodeboks ind/udKode 


Dvs. alle skibene efter hindanden fylder 1849 meter. Da den kongelige kaj er 2 kilometer lang kan kongen glædeligt annoncere at begivenhed finder sted.

Som du nok har regnet summerer SUM funktionen alle tallene i den angivne kolonne, i dette tilfælde Length-kolonnen.

Du kan putte DISTINCT foran kolonneangivelsen. I så tilfælde vil gentagne værdier kun blive medregnen én gang. Så hvis vi havde skrevet:

Fold kodeboks ind/udKode 


havde resultatet været 1758 i stedet for de oprindelige 1849 da kun den ene af de to værdier på 91 medregnes.

SUM som vi lige har set, er en mængdefunktion, også kaldet opsamlingsfunktion (eng.: aggrgation functions eller set function). Mægndefunktioner kan stå i en SELECT sætning. Hvis hele udtrykket ikke har en GROUP BY bisætning virker mængdefunktionerne på alle rækkerne i udtrykket, og resultatet er en resultatmængde indeholdende en enkelt række. Detfor kan en SELECT ikke indeholde både en mængdefunktion og en kolonneangivelse (udover dem der findes i selve mængdefunktionerne selvfølgelig). F.eks. er følgende SELECT ikke lovlig:

Fold kodeboks ind/udKode 


Denne SELECT sætning indeholder både en kolonne (Name) og en mængdefunktion (SUM). Brugen af SUM bevirker at resultatmængden kun indeholder en enkelt række med en kolonne der viser summen af Speed kolonnen fra alle tabellens rækker, hvorimod specificeringen af Name kolonnen bevirker at resultatmængden indeholer netop denne kolonne fra alle rækkerne i Ships-tabellen. Disse to resultater er selvsagt modsigende og kan derfor ikke begge opfyldes (vi kan ikke have en resultatmængde der indeholder kun en række og på samme tid indeholder alle rækkerne), hvorfor den er ulovlig.

En SELECT med en mængdefunktion vil altid resultere i én række, hverken flere eller færre. Rækken kan godt indeholde én eller flere NULL værdier. Derudover kan man ikke indlejre mængdefunktioner: SUM(MAX(..)) er altså ikke lovlig.

I forhold til NULL værdier gælder følgende:

*Hvis nogle af væriderne er NULL udelades de i selve berengingen.
*Hvis kolonnen kun indeholder NULL er resultatet NULL.

COUNT
Mængdefunktionen COUNT bruges til at finde ud af hvor mange rækker der er i en tabel. Hvis f.eks. vi ønsker at vide hvor mange skibe der er i vores Ships tabel, kan vi bruge følgende:

Fold kodeboks ind/udKode 


Her tæller vi hvor mange rækker i Ships der ikke har NULL værdier i Name-kolonnen.
Resultatet er:
Fold kodeboks ind/udKode 


Vi kan bruge DISTINCT til at finde ud af hvor mange rækker der findes med forskellige værdier. Hvor mange forskellige type motorer har vi i Ships-tabellen? Det finder følgende SELECT ud af:

Fold kodeboks ind/udKode 


Resultatet er her 9. DISTINCT fjerner altså alle gentagne værdier og udfører herefter additionen.

Et andet eksempel: Hvor mange forskellige tegn starter skibsnavnene med? Følgende SELECT finder ud af det for os:

Fold kodeboks ind/udKode 


Resultatet er:

Fold kodeboks ind/udKode 


Så kun tre forskellige tegn er det første i skibsnavnene - det skyldes at de fleste af navnene starter med "HM".

Vi kan også finde ud af i hvor mange forksellige år vi søsatte skibene i vores tabel:

Fold kodeboks ind/udKode 


Da alle skibene er søsat i 1905 er resultatet 1.

Som illustreret med COUNT kan du se at vi kan bruge alle former for udtryk i en mængdefunktion.

Vi kan også bruge to eller flere mængdefunktioner i samme SELECT:

Fold kodeboks ind/udKode 


Resultatet er:

Fold kodeboks ind/udKode 


AVG
AVG funktionen finder det aritmetiske gennemsnit af kolonneværdierne. AVG er blot en forkortelse for det engelske ord average som betyder aritmetisk gennemsnit (det aritmetiske gennemsnit kaldes også får middeltallet eller middelværdien. Det findes andre gennemsnit såsom det geometriske gennemsnit og harmoniske gennemsnit). Middelværdien af et datasæt er summen af pågældende værdier dividieret med antallet af værdier.

Så, hvad er middelværdien af hastigheden på skibene? Lad os finde ud af det med følgende SELECT sætning:

Fold kodeboks ind/udKode 


Resultatet er: 17,6092857142857. Så skibene i vores tabel har i gennemsnit en hastighed på 17,61 knob.

Du kan bruge DISTINCT sammen med AVG funktionen for at få et uvægtede gennemsnit. Med uvægtede menes at hver værdi kun medregnes én gang selvom de måtte eksistere i flere rækker. Hvad er det uvægtede gennemsnit af hastigheden:

Fold kodeboks ind/udKode 


Det er: 17,9608333333333.

Vi kan også bruge AVG til at finde den gennemsnitlige navnlængde på skibene:

Fold kodeboks ind/udKode 


Først fjerner vi med RTRIM eventuelle mellemrum efter navnet. Derefter bruger vi LEN til at finde længden på navnet, endelig finder mængdefunktionen AVG den gennemsnitlige længde.

Resultatet er:

Fold kodeboks ind/udKode 


Bemærk at i ovenstående SELECT er det kun AVG der af de tre funktioner er en mængdefunktion.

MIN/MAX
Disse to opsamlingsfunktioner kan bruges til at finde den mindste og største værdi i en kolonne. De kan anvendes på såvel numerisk- som tekstdata.

Hvor lang er det længste skib? Det finder følgende SELECT sætning ud af:

Fold kodeboks ind/udKode 


og resultatet er:

Fold kodeboks ind/udKode 


Så det længste skib er altså 205 meter. Hvad med det mindste skib?

Fold kodeboks ind/udKode 


Ovenstående SELECT fortæller os at det er 68 meter.

Hvad er det første bogstav i navent på det sidste (alfabetisk ment) skibsværft? Det kan vi finde ud af på følgende måde:

Fold kodeboks ind/udKode 


Resultatet er:

Fold kodeboks ind/udKode 


Her bruger vi MAX på en tekststreng og den finder det sidste navn alfabetisk.

Hvis MIN eller MAX bruges på en tom mængde er resultatet NULL. Det ses i følgende eksempel.

Fold kodeboks ind/udKode 


Denne SELECT referere en Builder værdi på 11 som ikke findes i vores tabel. Resultater er derfor NULL:

Fold kodeboks ind/udKode 


Endnu et eksempel. Lad os sige vi ønsker at udskrive det første, alfabetisk set, navn på skibe bygget af et givent værft og såfremt det pågældene værft ikke har bygget nogle skibe skal teksten "No ships built by shipyard!" udskrives. Det sørger følgende SELECT for:

Fold kodeboks ind/udKode 


Her skal @Builder erstattes med ID nummeret på pågældende skibsværft. Hvis vi f.eks. erstatter det med 5 bliver resultatet:

Fold kodeboks ind/udKode 


Hvis vi i stedet bruger 11 får vi:

Fold kodeboks ind/udKode 


I denne SELECT bruges MIN altså på tekst og finder det alfabetisk set mindste navn. Derudover anvender jeg et CASE udtryk for at udskrive en brugervenlig tekst såfremt resultatet af mængdefunktionene er NULL.

VAR/STDEV
Med funktionerne VAR og STDDEV (i MySQL hedder de VARIANCE og STDDEV), kan vi finde en kolonnes varians og stadard afgivelse. De kan selvsagt kun bruges på numerisk data.

Mængdefunktionen VAR udregner variansen på dets argument. Variansen er et udtryk for hvor tæt et datasæts værdier er på dets gennemsnit. Så variansen kan sige noget om hvor store afvigelser der er i datasættet. Lad os kigge på vores skibes afvigelse fra hastighedsgennemsnittet:

Fold kodeboks ind/udKode 


Resultatet er: 20,0593456043956.

Standard afvigelsen, også kaldet spredningen, er defineret som kvadratroden af variansen og kan i SQL Server findes med STDEV funktionen:

Fold kodeboks ind/udKode 


Resultatet er

Fold kodeboks ind/udKode 


Ligesom variansen siger spredgningen noget om hvor tæt på middelværdien datasættet er.

Spredningen bruges oftere end variansen ved vurdering af et datasæt. Vairansen er dog også vigtig, f.eks. i regressionsanalyse.

Referencer


Billederne i denne artikel er fra wikipedia og altså underlagt GNU Free Documentation License.

Hvis man vil læse lidt mere om SQL kan bogen "Introduction to SQL" af Rick F. van der Lans anbefales. Det er en stor bog; en SQL bibel kan man vist godt kalde den. Hvis man er nybegynder med SQL er "Head First SQL" et rigtig godt sted at starte.

Derudover kan alt fra C. J. Dates hånd anbefales. Ligeledes kan SQL bøger skrevet af Joe Celko stærkt anbefales; især "Celko's SQL Puzzles and Answers, Second Edition" er sjov og spændende.



<< < 123 > >>

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (5)

User
Bruger #6559 @ 07.02.08 19:34
En meget god artikel. Jeg synes der er mange gode ting, som man måske ikke lige er faldet over i andre artikler.

User
Bruger #2730 @ 08.02.08 09:54
Du skriver at følgende er ulovlig: select name, sum(speed)
Både ja og nej, den kan ikke eksekvere, der mangler en grupperings funktion. Så for at den skal virke skal den hedde select name, "sum(speed) group by name". Samtidig synes jeg starten er lidt malplaceret, du vil skrive om aggregeringsfunktioner, men starter ud med at have 2 sider om alt andet end aggregeringsfunktioner. Du er hurtigt omkring joins, men gør det ikke færdigt...

Det du dækker omkring aggregeringsfunktioner er godt og velskrevet
User
Bruger #4522 @ 08.02.08 11:17
Hej Brian,

Ang. SELECT name, sum(speed) værende ulovlig så tager jeg selvsagt ikke GROUP BY i betragtning i artiklen overhovedet, og det er med vilje da det er et stort emne for sig selv. Jeg kunne måske havde nævnt det forbehold mere eksplicit.

Meningen var at artiklen udelukkende skulle omhandle SELECT og mængdefunktioner, hverken GROUP BY eller FROM (og altså ej heller JOINs); artiklen var ikke ment til en nybegynder hvorfor jeg antog det rimeligt at læseren havde noget SQL viden i forvejen, og derfor kunne betragte emnerne i isolation.

Jeg medgiver dog at jeg muligvis kunne have gjort disse forbehold mere eksplicit. Du tydeliggør i hvert fald at jeg har fejlet hvad det angår.

Tak for dine kommentarer ;)
User
Bruger #11375 @ 17.02.08 01:11
Hej Jacob,

en virkelig superfed artikel som der simpelthen har været en fornøjelse at læse.

SQL er virkelig et fedt sprog med ret så mange muligheder. :-)

User
Bruger #8782 @ 20.06.08 16:07
Meget nyttig artikel, men mest for de brugere som har en lille smule forstand på MySQL vil jeg påskønne. :D
- Men jeg synes stadig artiklen er til en 5'er!

Og som Martin Th. Sonne siger, det var virkelig en fornøjelse at læse artiklen!
Du skal være logget ind for at skrive en kommentar.
t