# Business intelligence

## Hvad det er

Business intelligence, i daglig tale forkortet BI, er arbejdet med at gøre en
organisations egne data til rapporter, dashboards og analyser, som de mennesker,
der træffer beslutningerne, kan handle på. Som forled bruges næsten altid
forkortelsen, som i BI-værktøj.

Udtrykket er ældre end softwaren. I oktober 1958 bragte IBM Journal of Research
and Development en artikel af H. P. Luhn med titlen »A Business Intelligence
System«. Luhn beskrev et maskinelt system, der skulle tage de dokumenter, en
organisation modtager eller selv skriver, lave et automatisk resumé af hvert
enkelt, beskrive det ved et mønster af dets ord og sende det til de steder i
organisationen — Luhn kaldte dem action points — hvis interesseprofil passede.
Et sådant sted kunne være en enkelt person, en gruppe, en afdeling eller en hel
division. Han gav ordet business en bevidst bred betydning, enhver organiseret
aktivitet fra videnskab og handel til jura, offentlig forvaltning og forsvar, og
forstod intelligence som evnen til at se, hvordan de foreliggende fakta hænger
sammen, godt nok til at styre handlingen mod et mål. Efter at have gennemgået
teknikkerne gav han helheden et navn: »We call this a Business Intelligence
System.«

Luhns materiale var tekst. Nutidens BI arbejder mest med tal i tabeller, og
Kimball Groups beskrivelse af et datavarehus- og BI-system viser den sædvanlige
opbygning. I baglokalet (back room) hentes data fra kildesystemerne, renses,
gøres ensartede og indlæses. I forlokalet (front room) præsenteres de, ordnet
efter forretningsproces og gemt på det mest detaljerede niveau, med aggregerede
opsummeringer lagt oveni for at gøre det hurtigere. Øverst ligger
BI-applikationerne: ad hoc-forespørgsler, standardrapporter, dashboards og
scorecards samt tungere applikationer til analyse og data mining.

Det, der binder de to betydninger sammen, er Luhns spørgsmål: hvem har brug for
at vide dette, og hvordan når det frem til dem i en form, de faktisk læser?

## Hvorfor det betyder noget

Enhver organisation styrer allerede efter tal. Spørgsmålet er, om tallene
stemmer overens. Når salgsafdelingen tæller en ordre med fra den dag, kontrakten
underskrives, og økonomiafdelingen fra den dag, fakturaen sendes, møder de to
afdelinger op til samme møde med hver sit omsætningstal, og mødet går med
forskellen i stedet for beslutningen. Et BI-system tjener sig ind ved at
fastlægge én definition pr. nøgletal, beregne det ét sted og vise det samme tal
til alle, der spørger.

Luhns diagnose fra 1958 passer stadig på de fleste fælles rapportmapper. Han så
organisationer sprede information bredt for at være på den sikre side og
bemærkede, at modtagerne druknede i papir, så risikoen for, at intet nåede frem,
blev stor. Et dashboard med fyrre diagrammer gør det samme på en skærm. Luhns
middel var udvælgelse. Hvert modtagersted fik først kun løbenummer, titel og
forfatter på de dokumenter, systemet havde valgt til det. Derefter kunne det
dreje numrene på en telefon for at få resuméerne og bede om dem, det ville have,
i fuld længde. Hver gang det tog imod et dokument, blev profilen opdateret, så
udvælgelsen blev bedre med brugen. En god rapport i dag virker på samme måde:
den tager udgangspunkt i en person og en beslutning og viser de få tal,
beslutningen afhænger af.

Der er også en praktisk side. Databasen bag en applikation er bygget til dens
mange små læsninger og skrivninger. Et spørgsmål, der læser et helt års ordrer,
konkurrerer med de skrivninger, når det kører samme sted, og det er én grund
til, at BI-data som regel ligger i et separat lager, der fyldes efter en fast
plan. At holde det lager på det mest detaljerede niveau, som Kimball beskriver,
afgør, hvilke spørgsmål man stadig kan besvare næste år uden at skulle tilbage
til kilderne.

## Sådan ser det ud i praksis

Et typisk BI-spørgsmål: omsætningen i tredje kvartal 2026 fordelt på region og
produkt, med en subtotal for hver region og en samlet total. Med en tabel
`sales`, der har én række pr. salg med `sold_on`, `region`, `product` og
`amount`, besvarer standard-SQL det i én forespørgsel:

```sql
SELECT region,
       product,
       sum(amount)               AS revenue,
       GROUPING(region, product) AS level
FROM   sales
WHERE  sold_on >= DATE '2026-07-01'
AND    sold_on <  DATE '2026-10-01'
GROUP  BY ROLLUP (region, product)
ORDER  BY GROUPING(region), region, GROUPING(product), product;
```

Med en håndfuld eksempelrækker giver den:

```text
 region | product | revenue | level
--------+---------+---------+-------
 North  | Boots   |    1200 |     0
 North  | Jackets |     800 |     0
 North  |         |    2000 |     1
 South  | Boots   |     500 |     0
 South  | Jackets |    1500 |     0
 South  |         |    2000 |     1
        |         |    4000 |     3
```

`ROLLUP (region, product)` er en forkortelse for
`GROUPING SETS ((region, product), (region), ())`: hele listen, hvert kortere
præfiks af den og til sidst den tomme mængde, som lægger alle rækker sammen.
PostgreSQL-dokumentationen nævner den som det sædvanlige redskab til hierarkiske
data, for eksempel løn pr. afdeling, pr. division og for hele virksomheden.
`CUBE (region, product)` ville i stedet gruppere efter alle delmængder og dermed
tilføje en total for hvert produkt på tværs af regionerne.

En kolonne, der ikke indgår i rækkens grupperingsmængde, kommer tilbage som
NULL, og derfor har subtotalrækkerne tomme felter. `GROUPING(region, product)`
fortæller, hvilke kolonner det drejer sig om. Den returnerer en bitmaske med én
bit pr. argument, det sidste argument i den laveste bit, og en bit er 1, når
kolonnen ikke var grupperet i rækken. Altså markerer 0 en detaljerække, 1 en
subtotal for en region (produktet er ikke grupperet) og 3 den samlede total
(ingen af dem er grupperet). En rapport læser `level` for at afgøre, hvilke
rækker der skal stå med fed.

Virksomhedens
[ydelse inden for dataanalyse og BI-dashboards](/da/services/data-analytics-bi/)
beskriver målet som dashboards og rapporter, der viser de få tal, en beslutning
faktisk afhænger af, og som opdateres, uden at nogen beder om det. En
forespørgsel som denne er laget under sådan en rapport: totalerne beregnes én
gang, i databasen, og dashboardet tegner dem blot.

## Hvor det går galt

**To tal under samme navn.** Omsætning, aktiv kunde og kundeafgang har hver
flere rimelige definitioner, og hver rapport, der regner selv, vælger én. Skriv
hvert nøgletal ned én gang, med hvad det tæller, fra hvilken kilde og pr.
hvilken dato, og beregn det i databasen, for eksempel som et view, frem for i
hver rapports formler. Kimball kalder den sproglige del for forretningsmetadata:
hvilke data der findes, hvor de kommer fra, og hvad de betyder.

**Alt sendt til alle.** Et dashboard med snesevis af diagrammer og en
modtagerliste med hele afdelingen genskaber den oversvømmelse, Luhn ville
standse. Begynd med en navngiven person og den beslutning, vedkommende træffer,
vis de tal, beslutningen kræver, og nedlæg de rapporter, ingen har åbnet i et
kvartal.

**Rapporter, der gør applikationen langsom.** En tung forespørgsel mod den
primære database i et system i drift konkurrerer med de kunder, der bruger det.
Kør rapporteringen på en læsereplika eller i et separat datavarehus, der fyldes
efter en fast plan. Aggregater, der er dyre at beregne og efterspørges ofte, kan
lægges i et materialiseret view, der genopfriskes efter hver indlæsning.

**Totaler bygget af totaler.** Gennemsnittet af hver regions gennemsnitlige
ordreværdi er ikke virksomhedens gennemsnitlige ordreværdi, medmindre alle
regioner har lige mange ordrer. Antallet af forskellige kunder pr. måned kan
ikke lægges sammen til et kvartal, for en kunde, der købte både i juli og i
august, tælles to gange. Behold detaljerækkerne, og aggreger hvert niveau ud fra
dem. Grupperingsmængder gør netop det: hvert niveau i forespørgslen ovenfor
beregnes ud fra salgsrækkerne, ikke ud fra niveauet under.

**Et tomt felt med to betydninger.** Tilføj ét salg, hvor regionen er ukendt, og
forespørgslen ovenfor giver en detaljerække med tom region, en subtotal for den
med to tomme felter og en samlet total, også med to tomme felter. Med `CUBE`
bliver det værre: to rækker viser tom region og Boots, den ene for Boots solgt,
hvor regionen er ukendt, og den anden for Boots i alle regioner tilsammen.
PostgreSQL-dokumentationen advarer om, at en NULL i data ikke kan skelnes fra
den NULL, der står for en kolonne, som er grupperet væk. Brug `GROUPING()`,
aldrig `IS NULL`, til at finde subtotalrækker, og giv manglende værdier en
synlig betegnelse som »ukendt«, når data indlæses.

**Gårsdagens tal læst som dagens.** Når en natlig indlæsning fejler, bliver
dashboardet ved med at vise de sidste gode tal, og intet på skærmen fortæller,
at de er gamle. Skriv tidspunktet for den seneste vellykkede indlæsning på hver
rapport, og lad overvågningen sende en alarm til en navngiven person, når en
planlagt indlæsning ikke bliver færdig.

## Læs mere

- [A Business Intelligence System](https://doi.org/10.1147/rd.24.0314) — H. P.
  Luhns artikel i IBM Journal of Research and Development, oktober 1958, som
  udtrykket stammer fra.
- [Kimball Technical DW/BI System Architecture](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/technical-dw-bi-system-architecture/)
  — Kimball Groups gennemgang af baglokalet, præsentationsområdet,
  BI-applikationerne og metadata.
- [Table Expressions](https://www.postgresql.org/docs/current/queries-table-expressions.html)
  — PostgreSQL's reference for `GROUPING SETS`, `ROLLUP` og `CUBE` og for,
  hvordan NULL står i stedet for en kolonne, der ikke er grupperet.
- [Aggregate Functions](https://www.postgresql.org/docs/current/functions-aggregate.html)
  — funktionen `GROUPING` og dens bitmaske, med et gennemregnet eksempel.

<https://engineer.company/da/glossary/business-intelligence/>
