Databasernas grunder

vår 2026

4. Mer om SQL-språket

Datatyper och uttryck

I SQL-språket används datatyper och uttryck på samma sätt som i programmering. I tidigare kapitel har vi redan gått igenom en hel del exempel på olika SQL-kommandon. Låt oss nu studera SQL-språket ännu mer ingående.

Varje databashanterare implementerar datatyper och uttryck på sitt eget sätt, och det finns en hel del små skillnader i hur olika databashanterare fungerar. Det är därför klokt att kontrollera detaljerna i dokumentationen för den databashanterare som används.

Datatyper

När man definierar en tabell anges en datatyp för varje kolumn:

CREATE TABLE Movies (
  id INTEGER PRIMARY KEY,
  name TEXT,
  release_year INTEGER
);

Här är kolumnen name av typen TEXT (sträng) och kolumnen release_year av typen INTEGER (heltal). Dessa är de vanligaste datatyperna som finns tillgängliga under dessa namn i många databaser. Andra vanliga datatyper är till exempel TIMESTAMP (tidpunkt), REAL (flyttal) och BLOB (rådata).

TEXT vs. VARCHAR

Ett vanligt sätt att lagra en sträng i SQL är att använda typen VARCHAR där man anger den maximala längden på strängen inom parentes. Exempelvis betyder typen VARCHAR(10) att strängen kan innehålla högst 10 tecken.

Det här påminner om programmering från förr i tiden, då en sträng kunde representeras som en teckenarray med fast längd. Datatypen TEXT är smidigare att använda eftersom man inte behöver ange någon maximal längd på strängen.

Datatyper i SQLite

En ovanlig egenskap hos SQLite är att datatypen som anges vid tabellens definition bara är en riktlinje för vilken datatyp kolumnen bör ha. Vi kan dock bortse från denna riktlinje och till exempel lagra en sträng i en kolumn som egentligen är avsedd för heltal:

INSERT INTO Movies (name, release_year) VALUES ('Snövit', 'abc');

Dessutom kan datatypens namn vara vilken som helst sträng, även om SQLite inte har en sådan datatyp. Vi kan således till exempel definiera en kolumn där vi avser att lagra en tidpunkt:

CREATE TABLE Bookings (
  id INTEGER PRIMARY KEY,
  start_time TIMESTAMP,
  end_time TIMESTAMP,
  description TEXT
);

I SQLite finns inte TIMESTAMP som datatyp utan tidpunkter hanteras som strängar. Här anger dock kolumnens datatyp vilken typ av värde som är avsedd att lagras i kolumnen.

Uttryck

Ett uttryck är en del av ett SQL-kommando som har ett visst värde. Exempelvis i frågan

SELECT price FROM Products WHERE name = 'rädisa';

finns det fyra uttryck: price, name, 'rädisa' och name = 'rädisa'. Uttrycken price och name får sina värden från kolumnen i raden, uttrycket 'rädisa' är en strängkonstant och uttrycket name = 'rädisa' är booleskt.

Vi kan göra uttrycken mer komplexa på samma sätt som i programmering. Till exempel frågan

SELECT price * 5 FROM Products;

ger som svar varje produkts pris multiplicerat med fem. Frågan

SELECT name FROM Products WHERE price % 2 = 0;

hämtar de produkter vars pris är jämnt.

Ett bra sätt att testa SQL-uttryck är att interagera med databasen genom att ställa frågor som inte hämtar data från någon tabell utan enbart beräknar värdet av ett visst uttryck. Nedan följer ett exempel:

sqlite> SELECT 2 * (1 + 3);
8
sqlite> SELECT 'te' || 'st';
test
sqlite> SELECT 3 < 5;
1

Den första frågan beräknar värdet på uttrycket 2 * (1 + 3). Den andra frågan kombinerar strängarna 'te' och 'st' med hjälp av ||. Den tredje frågan bestämmer värdet av villkorsuttrycket 3 < 5. Här ser man att i SQLite representerar ett heltal ett booleskt (logiskt) värde där 1 är sant och 0 är falskt.

Mycket som rör SQL-uttryck är bekant från programmering:

Utöver dessa finns det i SQL även några mer speciella funktioner som kan vara nyttiga att känna till. Några av dessa är bland annat:

BETWEEN

Uttrycket x BETWEEN a AND b är sant om x är minst a och högst b. Exempelvis frågan

SELECT * FROM Products WHERE price BETWEEN 4 AND 6;

hämtar de produkter vars pris är minst 4 och högst 6. Samma fråga kan också skrivas på följande sätt:

SELECT * FROM Products WHERE price >= 4 AND price <= 6;

CASE

Strukturen CASE möjliggör skapandet av villkorsuttryck. CASE kan innehålla en eller flera WHEN-delar och en valfri ELSE-del. Exempelvis frågan

SELECT
  name,
  CASE WHEN price > 5 THEN 'dyr' ELSE 'billig' END
FROM
  Products;

hämtar varje produktnamn och information om produkten är dyr eller billig. Här räknas en produkt som dyr om priset är över 5. Om priset är 5 eller under 5 så räknas produkten som billig.

IN

Uttrycket x IN (...) är sant om x motsvarar något av de angivna värdena. Till exempel frågan

SELECT
  SUM(price)
FROM
  Products
WHERE
  name IN ('kålrot', 'rova', 'selleri');

hämtar det totala priset för kålroten, rovan och sellerin.

LIKE

Uttrycket s LIKE p är sant om strängen s överensstämmer med beskrivningen p. I beskrivningen kan man använda specialtecken. Tecknet _ betyder vilket enstaka tecken som helst och tecknet % betyder ett godtyckligt antal tecken. Till exempel frågan

SELECT * FROM Products WHERE name LIKE '%rot%';

hämtar de produkter i vilkas namn strängen “rot” förekommer (morot och kålrot)

Funktioner

Uttrycken kan innehålla funktioner på samma sätt som i programmering. Nedan är några exempel på funktioner i SQLite:

Följande fråga hämtar de produkter vars namn innehåller sex bokstäver (rädisa och kålrot)

SELECT * FROM Products WHERE LENGTH(name) = 6;

Följande fråga grupperar produkterna efter första bokstaven och visar antalet produkter som börjar med respektive bokstav.

SELECT
  SUBSTR(name, 1, 1), COUNT(*)
FROM
  Products
GROUP BY
  SUBSTR(name, 1, 1);

Följande fråga returnerar raderna i slumpmässig ordning eftersom ordningen inte baseras på innehållet i någon kolumn utan på ett slumpmässigt värde.

SELECT * FROM Products ORDER BY RANDOM();

ORDER BY och uttryck

Man kunde anta att i frågan

SELECT * FROM Products ORDER BY 1;

sorteras raderna enligt uttrycket 1, och eftersom uttryckets värde är 1 på varje rad så innebär detta ingen särskild ordning. Detta är dock inte fallet. 1 sorterar nämligen raderna efter den första kolumnen, 2 efter den andra kolumnen och så vidare. Detta är alltså ett alternativt sätt att ange vilken kolumn sorteringen ska baseras på.

Om uttrycket i ORDER BY-delen däremot är något annat än ett enstaka tal (till exempel RANDOM()), ordnas raderna enligt uttrycket i fråga.

NULL-värden

NULL är ett speciellt värde som anger att en kolumn i tabellen saknar information eller att en del av en fråga inte returnerade något värde. NULL kan vara praktiskt i vissa situationer, men kan också orsaka utmaningar.

Som standard visar SQLite-tolken värdet NULL som tomt:

sqlite> SELECT NULL;

NULL-värdet kan visas med tolken genom kommandot .nullvalue:

sqlite> .nullvalue NULL
sqlite> SELECT NULL;
NULL

Observera att NULL inte är talet 0. Om NULL ingår i en beräkning blir hela resultatet NULL.

sqlite> SELECT 5 + NULL;
NULL
sqlite> SELECT 2 * NULL + 1;
NULL

En vanlig jämförelse ger inte något svar om NULL ingår i jämförelsen:

sqlite> SELECT 5 = NULL;
NULL
sqlite> SELECT 5 <> NULL;
NULL

Svaret kan vara en aning oväntat. För uttrycken a och b gäller vanligtvis antingen a = b eller a <> b. Vi kan kontrollera om ett uttryck har värdet NULL med syntaxen IS NULL:

sqlite> SELECT 5 IS NULL;
0
sqlite> SELECT NULL IS NULL;
1

Information saknas i kolumnen

Ett av syftena med värdet NULL är att ange att en kolumn saknar information. Till exempel i följande tabell Movies saknas utgivningsåret för filmen Dumbo:

id  name       release_year
--  ---------  ------------
1   Snövit     1937        
2   Fantasia   1940        
3   Pinocchio  1940        
4   Dumbo      NULL        
5   Bambi      1942        

Om vi först hämtar filmer från år 1940 och sedan alla filmer från andra år, får vi följande resultat:

SELECT * FROM Movies WHERE release_year = 1940;
id  name       release_year
--  ---------  ------------
2   Fantasia   1940        
3   Pinocchio  1940        
SELECT * FROM Movies WHERE release_year <> 1940;
id  name     release_year
--  -------  ------------
1   Snövit   1937        
5   Bambi    1942        

Observera att eftersom filmen Dumbo saknar utgivningsår så finns den inte med i något av svaren. Vi kan hämta de filmer som saknar utgivningsår med följande fråga:

SELECT * FROM Movies WHERE release_year IS NULL;
id  name   release_year
--  -----  ------------
4   Dumbo  NULL        

Ett NULL-värde i en aggregeringsfunktion

När en aggregeringsfunktion innehåller ett uttryck (till exempel ett kolumnvärde) räknas raden inte med om uttryckets värde är NULL. Som exempel kan vi titta på följande tabell Employees:

id  name      company  salary
--  --------  -------  ------
1   Anna      Google   8000  
2   Liisa     Google   7500  
3   Kaaleppi  Amazon   NULL  
4   Uolevi    Amazon   NULL  
5   Maija     Google   9500  

I tabellen har Googles anställda ett angivet lönebelopp medan Amazons anställda inte har det. Aggregeringsfunktionen COUNT(salary) räknar endast med de rader där lönen är angiven:

SELECT COUNT(salary) FROM Employees WHERE company = 'Google';
COUNT(salary)
-------------
3

SELECT COUNT(salary) FROM Employees WHERE company = 'Amazon';
COUNT(salary)
-------------
0

När vi beräknar summan av lönerna med aggregeringsfunktionen SUM(salary) får vi följande resultat:

SELECT SUM(salary) FROM Employees WHERE company = 'Google';
SUM(salary)
-----------
25000      
SELECT SUM(salary) FROM Employees WHERE company = 'Amazon';
SUM(salary)
-----------
NULL

Svaret kan vara en aning oväntat eftersom man skulle kunna förvänta sig att en tom summa blir 0 istället för NULL.

Ändra NULL-värdet

Funktionen IFNULL(a, b) returnerar värdet a om a inte är NULL. Om a är NULL så returneras istället värdet b:

sqlite> SELECT IFNULL(5, 0);
IFNULL(5, 0)
------------
5          
sqlite> SELECT IFNULL(NULL, 0);
IFNULL(NULL, 0)
---------------
0

Ovanstående exempel är ett vanligt sätt att använda IFNULL(a, b) på. Funktionen omvandlar ett eventuellt NULL-värde till noll när den andra parametern (b) i IFNULL(a, b) är 0. Detta är användbart till exempel i LEFT JOIN-frågor tillsammans med SUM-funktionen.

Funktionen IFNULL är inte en standardfunktion i SQL och fungerar därmed inte i alla databashanterare. En standardfunktion i SQL är COALESCE(...), till vilken man ger en lista med värden. Funktionen returnerar det första värdet i listan som inte är NULL, eller NULL om alla värden i listan är NULL. Om funktionen endast har två parametrar fungerar den på samma sätt som IFNULL.

sqlite> SELECT COALESCE(1, 2, 3);
COALESCE(1, 2, 3)
-----------------
1              
sqlite> SELECT COALESCE(NULL, 2, 3);
COALESCE(NULL, 2, 3)
--------------------
2                 
sqlite> SELECT COALESCE(NULL, NULL, 3);
COALESCE(NULL, NULL, 3)
-----------------------
3                    
sqlite> SELECT COALESCE(NULL, NULL, NULL);
COALESCE(NULL, NULL, NULL)
--------------------------
NULL

Underfrågor

En underfråga är ett uttryck som ingår som en del av ett SQL-kommando och vars värde bestäms av en viss fråga. Vi kan formulera underfrågor på samma sätt som vanliga frågor och använda dem för att göra sökningar som annars vore svåra att genomföra.

Exempel

Låt oss betrakta en situation där databasen innehåller spelares resultat i tabellen Results. Vi antar att tabellen ser ut på följande sätt:

id  name      score
--  --------  -----
1   Uolevi    120  
2   Maija     80   
3   Liisa     120  
4   Aapeli    45   
5   Kaaleppi  115  

Vi vill nu ta reda på vilka spelare som har uppnått högsta poäng. Från tabellen ovan ser vi att det är Uolevi och Liisa som upnått högsta poäng. Vi kan utföra följande underfråga:

SELECT
  name, score
FROM
  Results
WHERE
  score = (SELECT MAX(score) FROM Results);

Frågan ger som svar:

name    score
------  -----
Uolevi  120  
Liisa   120  

I frågan ovan är underfrågan SELECT MAX(score) FROM Results. Underfrågan ger det bästa resultatet i tabellen som i det här fallet är 120. Observera att underfrågan måste skrivas inom parenteser för att den inte ska blandas ihop med huvudfrågan.

Skapa en underfråga

En underfråga kan förekomma nästan var som helst i frågan. En underfråga kan, beroende på situation, returnera ett enstaka värde, en lista med värden eller en hel tabell.

En underfråga i en kolumn

I följande fråga skapas med hjälp av en underfråga en tredje kolumn som visar spelarens poängskillnad från rekordresultatet:

SELECT
  name, score, (SELECT MAX(score) FROM Results) - score
FROM
  Results;
name      score  (SELECT MAX(score) FROM Results) - score
--------  -----  ----------------------------------------
Uolevi    120    0                                     
Maija     80     40                                    
Liisa     120    0                                     
Aapeli    45     75                                    
Kaaleppi  115    5                                     

Uttrycket som skapar kolumnen i resultattabellen är rätt invecklat. Resultattabellen kan göras tydligare genom att ge kolumnen ett nytt namn.

SELECT
  name,
  score,
  (SELECT MAX(score) FROM Results) - score AS difference
FROM
  Results;
name      score  difference
--------  -----  ----------
Uolevi    120    0         
Maija     80     40        
Liisa     120    0         
Aapeli    45     75        
Kaaleppi  115    5         

Underfråga som en tabell

I följande fråga skapar underfrågan en tabell med de tre bästa resultaten. Summan av dessa resultat (120 + 120 + 115) beräknas i huvudfrågan.

SELECT
  SUM(score)
FROM
  (SELECT * FROM Results ORDER BY score DESC LIMIT 3);
SUM(score)
----------
355

Här begränsar LIMIT resultattabellen så att den endast innehåller de tre första raderna.

Observera att vi skulle erhålla fel svar utan underfrågan:

SELECT SUM(score) FROM Results ORDER BY score DESC LIMIT 3;
SUM(score)
----------
480     

I denna resultattabell finns endast en rad med summan av alla resultat (480). LIMIT 3 i slutet av frågan påverkar därför inte alls resultatet.

Underfråga som en lista

Följande fråga hämtar spelare vars resultat hör till de tre bästa. Underfrågan returnerar resultatet som en lista för att användas i IN-uttrycket.

SELECT
  name
FROM
  Results
WHERE
  score IN (SELECT score FROM Results ORDER BY score DESC LIMIT 3);
name
----------
Uolevi    
Liisa     
Kaaleppi  

En underfråga som beror på huvudfrågan

Det är också möjligt att skapa en underfråga så att den beror på den rad som behandlas i huvudfrågan. Detta är fallet i följande fråga:

SELECT
  name,
  score,
  (SELECT COUNT(*) FROM Results WHERE score > R.score) AS better_count
FROM
  Results R;

Denna fråga räknar för varje spelare hur många spelares resultat som är bättre än spelarens eget resultat. Till exempel är svaret 3 för Maija, eftersom resultaten för Uolevi, Liisa och Kaaleppi är bättre. Frågan ger som svar följande:

name      score  better_count
--------  -----  ------------
Uolevi    120    0           
Maija     80     3           
Liisa     120    0           
Aapeli    45     4           
Kaaleppi  115    2           

Eftersom tabellen Results förekommer i två roller i underfrågan har tabellen i huvudfrågan getts aliaset R. Detta gör det tydligt i underfrågan att man vill räkna de rader vars resultat är bättre än resultatet på den rad som för tillfället behandlas i huvudfrågan.

Nedan är ett till exempel på en underfråga som beror på huvudfrågan:

SELECT
  name
FROM
  Results R
WHERE
  (SELECT COUNT(*) FROM Results WHERE score < R.score) >= 1;

Frågan söker de spelare som har ett bättre resultat än någon annan spelare. Underfrågan räknar hur många spelare som har ett sämre resultat och villkoret i huvudfrågan är att underfrågans resultat är minst ett. Det slutgiltiga svaret på frågan blir:

name
----------
Uolevi    
Maija     
Liisa     
Kaaleppi  

Frågan ger som svar alla spelare förutom Aapeli som har det sämsta resultatet.

I SQL finns också nyckelordet EXISTS som anger huruvida en underfråga returnerar åtminstone en rad. Med hjälp av detta nyckelord kan den föregående frågan skrivas tydligare:

SELECT
  name
FROM
  Results R
WHERE
  EXISTS (SELECT * FROM Results WHERE score < R.score);

När ska man använda underfrågor?

Rätt ofta är en underfråga ett alternativt sätt att ställa en fråga som också kunde ställas på något annat sätt. Till exempel hämtar båda frågorna nedan namnen på de produkter som finns i köpkorgen för kund 1:

SELECT
  Products.name
FROM
  Products, Purchases
WHERE
  Products.id = Purchases.product_id AND Purchases.customer_id = 1;
SELECT
  name
FROM
  Products
WHERE
  id IN (SELECT product_id FROM Purchases WHERE customer_id = 1);

Den första frågan är en typisk fråga som använder två tabeller medan den andra frågan väljer ut produkterna med hjälp av en underfråga. Vilken av dessa två frågor är bättre?

Den första frågan är bättre eftersom detta är det avsedda sättet att hämta information ur tabeller i SQL med hjälp av referenser. Den andra frågan fungerar visserligen, men följer inte standardpraxis och databashanteraren kan nödvändigtvis inte heller utföra den lika effektivt som den första frågan.

En underfråga bör endast användas när det verkligen behövs. Om frågan enkelt kan göras med en fråga som involverar flera tabeller är det vanligtvis en bättre lösning.

Fler tekniker

Detta avsnitt innehåller fler exempel på möjligheter i SQL. Dessa tekniker är användbara för att lösa vissa av de mer avancerade uppgifterna i SQL Trainer.

Kumulativ summa

En användbar färdighet i SQL är att kunna beräkna en kumulativ summa, det vill säga summan av kolumnvärden fram till varje rad. Låt oss titta på följande exempel med tabellen Items:

id  value
--  -----
1   200  
2   100  
3   400  
4   100  

Vi kan beräkna den kumulativa summan med en fråga som involverar två tabeller på följande sätt:

SELECT
  A.id, SUM(B.value)
FROM
  Items A, Items B
WHERE
  B.id <= A.id
GROUP BY
  A.id;
id  SUM(B.value)
--  ------------
1   200         
2   300         
3   700         
4   800         

Idén är här att summan beräknas för en rad i tabellen A och från tabell B hämtas alla rader vars id är mindre än eller lika med radens id i tabell A. De önskade summorna kan sedan beräknas med SUM-funktionen efter grupperingen.

En liknande teknik kan användas i andra situationer när vi vill beräkna ett resultat som på något sätt beror på alla “mindre” rader i tabellen.

Nästlade frågor

Låt oss betrakta en situation där vi vill ta reda på det största antalet filmer som har släppts under samma år. Till exempel i följande tabell Movies är det önskade resultatet 2 eftersom två filmer släpptes år 1940.

id  name       release_year
--  ---------  ------------
1   Snövit     1937        
2   Fantasia   1940        
3   Pinocchio  1940        
4   Dumbo      1941        
5   Bambi      1942        

Detta kan verka lite knepigt eftersom vi skulle behöva göra nästlade frågor med COUNT som räknar hur många filmer som släppts under samma år och MAX som hämtar det största värdet. SQL tillåter dock inte en fråga i stil med SELECT MAX(COUNT(release_year)).

Vi kan här utgå från en fråga som grupperar filmerna efter år och hämtar antalet filmer i varje grupp:

SELECT COUNT(*) FROM Movies GROUP BY release_year;
COUNT(*)  
--------
1         
2         
1         
1       

Nu ska vi ännu hämta det största värdet, vilket kan göras med en underfråga. Det är här praktiskt att forma frågan så att underfrågans resultat är i FROM-delen i huvudfrågan. Underfrågan skapar då en tabell som huvudfrågan sedan hämtar information ifrån:

SELECT MAX(year_count) FROM (
  SELECT COUNT(*) year_count FROM Movies GROUP BY release_year
);
MAX(year_count)
---------------
2       

Kan uppgiften lösas utan en underfråga? Ja. Vi kan nämligen sortera resultaten från störst till minst och välja den första raden i resultattabellen:

SELECT COUNT(*) AS year_count FROM Movies GROUP BY release_year
ORDER BY year_count DESC LIMIT 1;
year_count
----------
2          

Placeringar

Låt oss titta på tabellen Results som innehåller spelare och deras resultat:

id  name      score
--  --------  -----
1   Aapeli    45   
2   Kaaleppi  115  
3   Liisa     120  
4   Maija     80   
5   Uolevi    120  

Målet är att hämta raderna i resultatordning från störst till minst och dessutom ange varje rads placering. Ett sätt att göra detta är att skapa en underfråga som räknar hur många rader som har ett bättre resultat, varpå placeringen blir ett högre än underfrågans resultat:

SELECT
  (SELECT COUNT(*) FROM Results WHERE score > R.score) + 1 AS place,
  name, score
FROM
  Results R
ORDER BY
  score DESC, name;
place  name      score
-----  --------  -----
1      Liisa     120  
1      Uolevi    120  
3      Kaaleppi  115  
4      Maija     80   
5      Aapeli    45   

Enligt samma princip kan placeringar beräknas så att varje spelare får en unik plats och vid lika resultat avgör alfabetisk ordning placeringen:

SELECT
  (SELECT COUNT(*) FROM Results WHERE score > R.score OR
    (score = R.score AND name < R.name)) + 1 AS place,
  name, score
FROM
  Results R
ORDER BY
  score DESC, name;
place  name      score
-----  --------  -----
1      Liisa     120  
2      Uolevi    120  
3      Kaaleppi  115  
4      Maija     80   
5      Aapeli    45   

Ett alternativt sätt att beräkna placeringar är med en fönsterfunktion, förutsatt att databashanteraren som används tillåter det. Till exempel kan man i nyare versioner av SQLite använda fönsterfunktionen RANK för att beräkna motsvarande placeringar som i de tidigare exemplen.

SELECT
  RANK() OVER (ORDER BY score DESC) place, name, score
FROM
  Results
ORDER BY
  place, name;
place  name      score
-----  --------  -----
1      Liisa     120  
1      Uolevi    120  
3      Kaaleppi  115  
4      Maija     80   
5      Aapeli    45   
SELECT
  RANK() OVER (ORDER BY score DESC, name) place, name, score
FROM
  Results
ORDER BY
  place, name;
place  name      score
-----  --------  -----
1      Liisa     120  
2      Uolevi    120  
3      Kaaleppi  115  
4      Maija     80   
5      Aapeli    45   

Jämförelse av listor

Låt oss betrakta tabellen Lists som består av innehållet i olika listor. Till exempel innehåller lista 1 talen [2, 4, 5], lista 2 talen [3, 5] och lista 3 talen [2, 4, 5]:

id  list_id  value
--  -------  -----
1   1        2    
2   1        4    
3   1        5    
4   2        3    
5   2        5    
6   3        2    
7   3        4    
8   3        5    

Följande fråga räknar för varje par av listor hur många gemensamma tal de har:

SELECT
  A.list_id, B.list_id, COUNT(*)
FROM
  Lists A, Lists B
WHERE
  A.value = B.value
GROUP BY
  A.list_id, B.list_id;
list_id  list_id  COUNT(*)
-------  -------  --------
1        1        3       
1        2        1       
1        3        3       
2        1        1       
2        2        2       
2        3        1       
3        1        3       
3        2        1       
3        3        3       

Här framgår det att till exempel listorna 1 och 2 har ett gemensamt tal (5) och listorna 1 och 3 har tre gemensamma tal (2, 4, 5). En sådan här fråga kan man bygga vidare på och till exempel jämföra om två listor har exakt samma innehåll. Detta är fallet när listorna har lika många tal och antalet gemensamma tal är lika stort som antalet tal i varje enskild lista.