Overview of registers

Variable names for the most commonly used DST registers

Published

September 9, 2026

A starting point, not an authority. This page can be out of date or simply wrong, and your own delivery may differ from it. Verify against your files with colnames() (see Phase 7 - Inspect your data) before you rely on anything here. Found a mistake? Open an issue or use the feedback box at the bottom - corrections are genuinely welcome.

Where this comes from, and why it can still be wrong

The tables on this page are generated from a schema built out of DST’s published documentation: the variable list for each register and DST’s order list, which names every variable in every DST register with its period. The health registers - LPR, LMDB, the death registers, the cancer register - are documented by Sundhedsdatastyrelsen on esundhed.dk instead, which is also the only source that publishes data types.

Each register links to its own source, and every value set says underneath where its codes come from.

Those sources change. Registers are extended, columns are added and retired, and a code can change meaning without changing its name. Names here are shown after rename_with(tolower), and your own delivery may spell them differently or not contain them at all: what DST documents is the register, not what your project ordered.

Key columns - the ones you actually use in the code - are marked in bold. Names apply after rename_with(tolower). See Pitfalls for the quirks of each register.

How to read the code examples: read_register() vs open_dataset()

The code on this page opens registers with read_register("registername") (fastreg, by name - recommended). That requires fastreg set up with the path to your registers, see Parquet and fastreg if you did not convert them from SAS yourself.

Without fastreg, use open_dataset("path/to/register/") instead and replace the path with your project’s parquet folder. Everything else in the examples works the same either way.

Looking for a particular variable? Find a variable searches every column in every register at once - the way to see how the same thing is named and coded differently from one register to the next.

Where to look things up

This page shows the columns most studies use. When you need more than that, the question you are asking decides where to go:

Your question Where to look
What are all the columns in this register? The register’s own variable list - follow the register name in the table below
Does this register reach the end of my follow-up? Datasafari - shows the latest reference date and the next expected update
Which registers exist at all, and which are closed? Oversigt over registre - over a thousand, with years covered. Luk means closed and never extended, as dodsaars and dodsaasg both are
Can I even order this variable, and for which years? Bestillingsliste.xlsx - every variable in every DST register, with its period. The one to open while you are still planning
What does code 330 mean? Klassifikationer - DISCED-15 for education, SOCIO for employment, DISCO for occupation
Why does this variable jump in one particular year? Højkvalitetsdokumentation - breaks in the series and validity periods, for selected variables
What does DST mean by “beskæftiget”? Hvad betyder - the words, not the columns. Look here when a variable measures something narrower than the everyday word suggests

All of it hangs off Dokumentation af data →, DST’s own hub, if you would rather start there. The health registers are documented separately by Sundhedsdatastyrelsen on esundhed.dk.

And whichever you use: what DST holds is not what your project was delivered. Confirm against your own files with colnames().

Overview - all registers

Register Read as Join key Period Often used
AKM "akm" pnr 1976 to 2024 socio13, socio02, socio
BEF "bef" pnr 1985-12 to 2026-06 koen, foed_dag, familie_id
CANCER "cancer" k_cprnr 1943 to 2024 c_icd10, c_morfo03, c_topo3
DOD "dod" pnr 1970 to 2025 doddato
DODSAARS "dodsaars" pnr 1970 to 2001 d_dodsdto, c_dodsmaade, c_dod1
DODSAARSAGER "dodsaarsager" pnr 2022 to 2024 doedsdato, doedsaarsag_tilgrundliggende, doedsaarsag_kode_1
DODSAASG "dodsaasg" pnr 2002 to 2022 d_dodsdato, c_dodtilgrundl_acme, c_dod_1a
FAIK "faik" familie_id 1987 to 2024 pnr, famaekvivadisp_13, year
LAB_DM_FORSKER "lab_dm_forsker" patient_cpr 2008 to 2025 samplingdate, analysiscode, value
LMDB "lmdb" pnr 1995-12 to 2025-12 eksd, atc, atc1
LPR_A_DIAGNOSE "lpr_a_diagnose" dw_ek_kontakt 2019 to 2025 diag_kode, diag_kode_type, senere_afkraeftet
LPR_A_KONTAKT "lpr_a_kontakt" dw_ek_kontakt 2017 to 2025 dw_ek_forloeb, pnr, kont_starttidspunkt
LPR_A_PROCREGISTRERING "lpr_a_procregistrering" dw_ek_kontakt 2019 to 2025 proc_kode, proc_starttidspunkt, proc_kode_type
LPR_ADM "lpr_adm" recnum 1977 to 2019-03 pnr, d_inddto, d_uddto
LPR_DIAG "lpr_diag" recnum 1977 to 2019-03 c_diag, c_diagtype, c_tildiag
LPR_SKSOPR "lpr_sksopr" recnum 1996 to 2019 c_opr, c_oprart, c_osgh
LPR_SKSUBE "lpr_sksube" recnum 1999 to 2019 c_opr, d_odto, year
MFR "mfr" cpr_barn 1997 to 2018 alder_moder, bmi_moder, cpr_moder
SSSY "sssy" pnr 2005 to 2025 ydernr, speciale, ydlant
SYSI "sysi" pnr 1990 to 2005 ydernr, speciale, ydlant
T_PSYK_ADM "t_psyk_adm" recnum 1995 to 2019 pnr, c_pattype, c_adiag
T_PSYK_DIAG "t_psyk_diag" recnum 1995 to 2019 c_diag, c_diagtype, c_tildiag
UDDA "udda" pnr 1980-12 to 2025-09 hfaudd, udd, hf_vfra
VNDS "vnds" pnr 1973 to 2024 indud_kode, haend_dato, indud_land
VNDS_HIST "vnds_hist" pnr 1973 to 2004 indud_kode, haend_dato, indud_land
VNDS_IND "vnds_ind" pnr 2005 to 2025 haend_dato, indv_land, indvmd
VNDS_UD "vnds_ud" pnr 2005 to 2025 haend_dato, udv_land, udvmd

The Often used column is the handful of columns most studies reach for, not the full list: follow the register link for every column DST documents, or the section below for the ones this guide explains. lab_dm_forsker is in the schema but not in this table, because it is reached through Sundhedsdatastyrelsen’s Forskerservice rather than DST.

1. Demographics and deaths

BEF - Population Register

Status register - one snapshot per person per reference time point. Delivered quarterly since 2008 (March, June, September, December); before 2008 December only. Whether year == 2020 corresponds to a particular reference time point depends on the project convention - confirm in your project guide. A person who dies during 2020 still appears in the 2020 snapshot - use DOD to determine whether a person was alive on a specific date.

BEF cannot on its own answer whether a person was resident in Denmark on a given date: between two snapshots people can both leave and come back. To decide residence on an index date, combine BEF with VNDS - see Phase 10 - the source population.

Column Type Role Label Years
pnr character join key Personal identifier 1985 to 2026
koen numeric code Sex 1985 to 2026
foed_dag date date Date of birth 1985 to 2026
familie_id character join key Household key 1985 to 2026
reg character code Region 1985 to 2026
civst character code Marital status 1985 to 2026
kom character code Municipality code 1985 to 2026
year integer date Register year
alder numeric value Age at the reference time point 1985 to 2026
opr_land numeric code Country of origin 1985 to 2026
referencetid date date Reference time point 1985 to 2026
All other columns (30)
Column Type Role Label Years
mor_id character identifier Mother’s person id 1985 to 2026
far_id character identifier Father’s person id 1985 to 2026
aegte_id character identifier Spouse id 1985 to 2026
e_faelle_id character identifier Cohabiting partner id 1985 to 2026
fdato date date Date of birth, CPR form
antboernf numeric value Number of children in the family 1985 to 2026
antboernh numeric value Number of children in the household 1985 to 2026
antpersf numeric value Number of people in the family 1985 to 2026
antpersh numeric value Number of people in the household 1985 to 2026
antefam numeric value Number of E-families in the household 1985 to 2026
familie_type numeric code Family type 1985 to 2026
fam_koen numeric code Sex of the family’s reference person 1985 to 2026
plads numeric code Position in the family 1985 to 2026
hustype numeric code Household type 1985 to 2026
fm_mark numeric code Parent marker 1985 to 2026
civ_vfra date date Date the marital status took effect 1985 to 2026
bop_vfra date date Date of moving in or immigrating 1985 to 2026
ie_type numeric code Immigrant, descendant or Danish origin 1985 to 2026
foedreg_kode numeric code Place of birth registration 1985 to 2026
statsb numeric code Citizenship 1985 to 2026
opholdmd_dk numeric value Months of residence in Denmark 1985 to 2026
van_vtil date date Immigration date 1985-12 to 2003-12
foerste_indvandring date date First immigration date 2004-12 to 2026-06
seneste_indvandring date date Most recent immigration date 2004-12 to 2026-06
adresse_id character identifier Address id 1985 to 2026
fkirk character code Membership of the Danish National Church 2004-12 to 2026-06
cprtjek character code CPR check 2004-12 to 2026-06
cprtype character code CPR type 2004-12 to 2026-06
version numeric code Module data version 2004-12 to 2026-06
betalingskom character code Betalingskommune 1985 to 2026
  • mor_id: A pnr-like identifier for the mother, so BEF can be turned into a family structure without a separate register. It is only filled where the link is registered, which is not the case for everyone born before CPR.
  • fdato: Not on DST’s variable list for BEF, which documents foed_dag instead. Present in this delivery. Prefer foed_dag unless you have checked what yours contains.
  • antefam: A household can hold several families. That is why the family counts and the household counts differ, and why FAIK’s household income cannot be read as one family’s income without checking this.
  • van_vtil: Ends December 2003 and is replaced by foerste_indvandring and seneste_indvandring. A study spanning 2003 has to read both, or it silently loses immigration dates on one side of the break.
  • foerste_indvandring: Begins December 2004. Before that the information is in van_vtil.
  • adresse_id: Identifies a dwelling, so two people with the same value live at the same address. It is not a geographic coordinate and cannot be decoded into one.

No published source gives a data type for 1 of these 41 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • familie_id joins to FAIK (many-to-one).
Value sets for the coded columns (9)
Code system Values
koen 1 Mand, 2 Kvinde, 9 Uoplyst
reg 0 Uoplyst, 81 Nordjylland, 82 Midtjylland, 83 Syddanmark, 84 Hovedstaden, 85 Sjælland
civst U Ugift, G Gift (+ separeret), F Skilt, E Enke/Enkemand, P Registreret partnerskab, O Ophævet partnerskab, L Længstlevende af 2 partnere, D Død, 9 Uoplyst civilstand
kom Not listed here - see DST’s classification
familie_type 1 Ægtepar, 2 Registreret partnerskab, 3 Samlevende par, 4 Samboende par, 5 Enlig (herunder også ikke hjemmeboende børn), 7 Ægtepar forskellig køn, 8 Ægtepar samme køn, 9 Enlig, 10 Ikke hjemmeboende børn
plads 1 Hovedperson, 2 Ægtefælle/partner, 3 Hjemmeboende barn
hustype 1 Enlig mand, 2 Enlig kvinde, 3 Ægtepar, 4 Par i øvrigt, 5 Ikke hjemmeboende børn (under 18 år), 6 Andre husstande bestående af flere familier
fm_mark 1 Bor sammen med begge forældrene, 2 For børn: Bor hos mor, der er i nyt par. For voksne: Bor sammen med mor, 3 For børn: Bor hos enlig mor. For voksne: Værdien findes ikke, 4 For børn: Bor hos far, der er i nyt par. For voksne: Bor sammen med far, 5 For børn: Bor hos enlig far. For voksne: Værdien findes ikke, 6 Bor ikke hos forældrene
herkomst 1 Personer med dansk oprindelse, 2 Indvandrere, 3 Efterkommere, 9 Uoplyst
  • koen: DST’s classification KOEN_V1_1980 also defines 9 for not stated, which a delivery may not contain but a value set should. Sex is taken from the tenth digit of the CPR number: even is female, odd is male.
  • reg: Do not confuse these with AMT, the pre-2007 counties, which has 16 codes in the ranges 11-14, 21-24, 31-37 and 88. Different geography, different era.
  • civst: Codes P, O and L came in with the registered-partnership act of 1 October 1989; before that the set was smaller. Registered partnerships could no longer be entered into from 15 June 2012.
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.
  • familie_type: There is no code 6, and the set changed in December 2015. Codes 7 and 8 split the old “Ægtepar” by sex, and codes 9 and 10 split the old “Enlig”, which had included children not living at home. A series that crosses 2015 therefore changes composition without any code going missing: 1 and 5 stop being used and four new codes appear. The exact switch-over dates are on DST’s page and should be read there before a study is dated around them.
  • fm_mark: Codes 3 and 5 occur for children only. For an adult the value does not exist, so an adult cohort holding them means the row is not what you think.
  • herkomst: A descendant is born in Denmark: neither parent is both a Danish citizen and born in Denmark. So the category says something about the parents, not about where the person was born, and it does not change over a lifetime the way citizenship does.

Where these values come from:

Worth knowing:

  • pnr: A person appears once per snapshot, not once in total. Taking a single year loses people who were resident but not in that particular snapshot, so a population is built from the union of all snapshots in the window.
  • year: Not a DST variable. It comes from the parquet conversion, which concatenates the yearly deliveries, so it exists in the data you read but not in DST’s own documentation of BEF. Because it is made rather than delivered, the name is not guaranteed: check colnames() rather than assuming.
  • alder: Age at the snapshot, not at any date you choose. Recompute from foed_dag and your own index date rather than reusing it.
  • referencetid: The date the snapshot describes. Every other column in the row is a status as of this moment, which is what makes BEF a status register rather than an event register.

BEF does not contain date of death. Use DOD (doddato) for censoring, not DODSAARS, which stops in 2001 (see below). DST’s own documentation: statistikdokumentation/befolkningen →.

DOD - Death Register

Døde i Danmark. One row per deceased person, covering 1970-2025 and still updated (DST register overview, last reference date 31 December 2025). This is the register you use to censor at death. It is a short one:

Column Type Role Label
pnr character join key Personal identifier
doddato date date Date of death
All other columns (3)
Column Type Role Label
alder_haend integer value Age at the time of death
cprtjek character value CPR check
cprtype character value CPR type

No published source gives a data type for 5 of these 5 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).

Worth knowing:

  • doddato: This is the column to censor on. Not d_dodsdto, which belongs to DODSAARS and stops in 2001.
DOD may not be in parquet on your project

DOD is sometimes delivered only as a raw SAS file, in which case read_register("dod") will not find it and you read it with haven::read_sas() instead. Ask your data manager for the path. And check the span of your own delivery, which is the years your project ordered rather than everything DST holds:

dod %>% summarise(min(doddato), max(doddato)) %>% collect()

DODSAARS - Cause of Death Register (ends 2001)

Dødsårssagsregistret. One row per deceased person, with the cause of death. It carries a death date too, in d_dodsdto, which is why it is so often used for censoring - but its coverage stops on 31 December 2001. Use it for causes of death up to 2001, and use DOD for the date.

Censoring on dodsaars silently treats everyone who died after 2001 as alive. No error, no warning: they simply stay in your risk set to the end of follow-up, so survival looks better than it is and rates come out too low. The full version of this is pitfall 1 - three death registers.

Column Type Role Label
pnr character join key Personal identifier
d_dodsdto date date Date of death
c_dodsmaade character code Manner of death
c_dod1 character code Underlying cause of death
c_dod2 character code Contributing cause of death 2
c_dod3 character code Contributing cause of death 3
c_dod4 character code Contributing cause of death 4
year integer date Register year
All other columns (27)
Column Type Role Label
c_dodskom character code Municipality of death
c_attart character code Type of certificate
c_sex character code Sex
v_alder numeric value Age at death
daar integer date Year of death
c_bopkom character code Municipality of residence at death
c_handsted character code Place of the event
c_liste_14 character code Cause group, 14-item list
c_liste_49 character code Cause group, 49-item list
c_liste_65 character code Cause group, 65-item list
cprtjek character code CPR-tjek
cprtype character code CPR-type
c_aldertim numeric value Dødsalder i timer
c_atckode1 character code C_ATCKODE1
c_atckode2 character code C_ATCKODE2
c_atckode3 character code C_ATCKODE3
c_atckode4 character code C_ATCKODE4
c_civstd character code Civilstand
c_institut character code Institution for dødsfald
c_obduktio character code C_OBDUKTIO
c_operatio character code Operationstilkendegivelse
c_u28dg numeric value Angivelse af dødsalder under 28 dage
c_ulyktype character code C_ULYKTYPE
v_aldermdr numeric value Alder i måneder
v_bopamt numeric value V_BOPAMT
v_dodsamt numeric value Dødsstedsamt
v_klok numeric value Tiden for dødens indtræffelse

DST publishes no labels for 4 of these columns. Where the Label column is filled in anyway, it is this guide’s reading of the column name, not an official description.

No published source gives a data type for 29 of these 35 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (5)
Code system Values
c_dodsmaade 1 Naturlig død, 2 Ulykke, 3 Selvmord, 4 Drab/vold, 5 Uoplyst
kom Not listed here - see DST’s classification
icd10 Not listed here - see DST’s classification
atc Not listed here - see DST’s classification
icd8 Not listed here - see DST’s classification
  • c_dodsmaade: Two separate traps. First, this code set is NOT the one used from 2002: in dodsaasg the same column holds c_dodsmaade_2002, where 1 is Voldshandling rather than Naturlig død. Second, code 4 changed meaning. It was Selvmord until 31 December 1990 and Drab/vold from 1 January 1991. dodsaars runs from 1970 to 2001 and so contains both, in one column, with nothing to tell them apart except the date of death. Reading code 4 as one thing across the whole register counts homicides as suicides or the reverse. Codes 6 (Drab/vold) and 9 (Uoplyst) belong only to the old set and stop at the end of 1990; codes 3 and 5 only start in 1991.
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.
  • icd10: Do not strip a leading D from these codes. The habit comes from LPR, where the D is really there, and applying it here removes the first character of a real code: E119 becomes 119, which matches nothing and raises no error. The danger is worst where a code genuinely begins with D. ICD-10 chapter D covers in-situ and benign neoplasms, so D46 is myelodysplastic syndrome, a whole code. Strip its “prefix” and you get 46, which looks like a code and is not one.
  • atc: As a rule, filter on the full 7-character code rather than on the level columns: atc2 holds three characters, so a longer pattern matched against it can never match, and it returns nothing at all with no error. The level columns are well suited to grouping, and to filtering when every code you want is the same length as the column.
  • icd8: A study whose period starts before 1994 is reading two classifications out of one column. ICD-10 codes match nothing in the early years, and the usual substr(c_diag, 2, 4) returns a meaningless fragment of an ICD-8 code rather than failing, so nothing tells you it went wrong.

Where these values come from:

Worth knowing:

  • d_dodsdto: A date of death exists here, but the register stops in 2001. Censor on DOD instead, which covers the whole period.
  • c_dod1: The underlying cause. Coded in the ICD revision in force at the time of death, so the code system changes inside the register’s own lifetime.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

DODSAARSAGER - the current register (2022 onwards)

Column Type Role Label
pnr character join key Personal identifier
doedsdato date date Date of death
doedsaarsag_tilgrundliggende character code Underlying cause of death
doedsaarsag_kode_1 character code Cause of death, code 1
doedsmaade_kode character code Manner of death
All other columns (34)
Column Type Role Label
doedsaarsag_liste_14_kode character code Cause group, 14-item list
doedsaarsag_liste_49_kode character code Cause group, 49-item list
doedssted_kode character code Place of death
dw_ek_borger character code Citizen key
flag_valideret character code Validated flag
borger_alder_doedsstatus numeric value
borger_bo_kom_doedsstatus character code
borger_bo_reg_doedsstatus character code
borger_koen_doedsstatus character code
cprtjek character code
cprtype character code
doedsaarsag_gruppering_a_kode character code
doedsaarsag_gruppering_b_kode character code
doedsaarsag_kode_2 character code
doedsaarsag_kode_3 character code
doedsaarsag_kode_4 character code
doedsaarsag_kode_a character code
doedsaarsag_kode_b character code
doedsaarsag_kode_c character code
doedsaarsag_kode_d character code
doedsstatusdato date date
doedssted_praecisering_kode character code
doedstidspunkt date date
findedato date date
findested_kode character code
findested_praecisering_kode character code
findetidspunkt date date
haendelsessted_kode character code
hospice character code
laegefunktion_kode character code
obduktionstype_kode character code
sygehus_org_reg character code
sygehus_shaksghkode character code
sygehus_sorkode character code
  • dw_ek_borger: An LPR3-style surrogate key alongside pnr. Not present in the two older cause-of-death registers.

DST publishes no labels for 10 of these columns. Where the Label column is filled in anyway, it is this guide’s reading of the column name, not an official description.

No published source gives a data type for 39 of these 39 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (1)
Code system Values
icd10 Not listed here - see DST’s classification
  • icd10: Do not strip a leading D from these codes. The habit comes from LPR, where the D is really there, and applying it here removes the first character of a real code: E119 becomes 119, which matches nothing and raises no error. The danger is worst where a code genuinely begins with D. ICD-10 chapter D covers in-situ and benign neoplasms, so D46 is myelodysplastic syndrome, a whole code. Strip its “prefix” and you get 46, which looks like a code and is not one.

Where these values come from:

Every register in the chain renames the same thing. The cause columns are c_dod1 to c_dod4 here, c_dod_1a to c_dod_1d in DODSAASG from 2002, and doedsaarsag_kode_1 and so on in DODSAARSAGER from 2022. The date column goes d_dodsdto, d_dodsdato, doedsdato - one letter between the first two.

Code written for one part of the chain will not run against another, and a mistyped column name fails as a missing column rather than a wrong answer.

Cause of death is split across three registers, by period. dodsaars runs to 2001, dodsaasg covers 2002-2022, and dodsaarsager takes over from 2022. Each one stops where the next begins, so a study spanning more than one of those windows needs all the registers that overlap its period, chained together. A single one gives you a silently incomplete picture: causes simply stop appearing after its last year.

None of the three is the source for the date of death. For that, use DOD with the column doddato. The cause coding itself is documented by the Danish Health Data Authority: Dødsårsagsregisteret →.

Do you ever need both DOD and DODSAARS?

Only if your own DOD delivery does not reach back far enough for your study period. Then stack them, renaming so the date columns match, and note that the two registers overlap for 1970-2001 - so without the distinct() every early death is counted twice:

deaths <- bind_rows(
  dod %>% select(pnr, death_date = doddato),
  dodsaars %>% select(pnr, death_date = d_dodsdto)
) %>%
  mutate(death_date = as.Date(death_date)) %>%
  distinct(pnr, .keep_all = TRUE) # keeps the DOD row, since it comes first

On DARTER, see Register paths and datastores.

VNDS - Migration Register

One row per migration event per person.

VNDS was closed in February 2026 and split into three registers (VNDS_ind, VNDS_ud, VNDS_hist, described below). It is still documented here because it is the only migration register many projects have: a delivery made before the split will not contain the replacements.

Check colnames() or your project’s register list to see which you have. If you have both, use the new ones and do not mix them with VNDS, or you will count the same migration twice. For emigration dates used in censoring, combine VNDS_ud (2005+) and VNDS_hist (1973-2004) in place of the old VNDS.

What the three replacement registers are, and why DST split them
  • VNDS_ind: immigrations to Denmark from 2005 onwards.
  • VNDS_ud: emigrations from Denmark from 2005 onwards.
  • VNDS_hist: historical migrations 1973-2004, no longer updated.

The split reduces duplicates that arose because immigration and emigration data came from different sources over the years. The earliest data is now frozen in the historical register. Source: DST notice, 19 February 2026.

Column Type Role Label
pnr character join key Personal identifier
indud_kode character code Immigration or emigration
haend_dato date date Date of the migration event
indud_land character code Country migrated from or to
All other columns (2)
Column Type Role Label
cprtjek character value CPR check
cprtype character value CPR type

No published source gives a data type for 6 of these 6 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (1)
Code system Values
indud_kode I Indvandring, U Udvandring
  • indud_kode: Use U for censoring at emigration. People who never emigrated have no U event at all, so they are simply absent rather than carrying a missing date. Two caveats from the guide: CPR only has complete immigration and emigration data from 1971, so someone who immigrated before that has no event and looks resident since birth; and a move to Greenland is a status of its own in CPR rather than an emigration. Confirm the values on your own delivery.

Where these values come from:

Worth knowing:

  • indud_land: Not listed in the guide’s own table. The country code set has not been sourced.

Use: filter(indud_kode == "U")min(haend_dato) per pnr for first emigration date. Non-emigrants do not appear in VNDS with a “U” event and get emigration_date = NA.

VNDS_hist - historical migrations (1973-2004)

Column Type Role Label
pnr character join key Personal identifier
indud_kode character code Immigration or emigration
haend_dato date date Date of the migration event
indud_land character code Country migrated from or to
All other columns (2)
Column Type Role Label
cprtjek character value
cprtype character value

No published source gives a data type for 6 of these 6 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (1)
Code system Values
indud_kode I Indvandring, U Udvandring
  • indud_kode: Use U for censoring at emigration. People who never emigrated have no U event at all, so they are simply absent rather than carrying a missing date. Two caveats from the guide: CPR only has complete immigration and emigration data from 1971, so someone who immigrated before that has no event and looks resident since birth; and a move to Greenland is a status of its own in CPR rather than an emigration. Confirm the values on your own delivery.

Where these values come from:

VNDS_ind - immigrations (2005 onwards)

The two new registers drop indud_kode: which direction the event went is now carried by which register you are reading, so a combined series has to add the direction back itself.

Column Type Role Label
pnr character join key Personal identifier
haend_dato date date Date of immigration
indv_land character code Country immigration from
indvmd character date Month of immigration
All other columns (18)
Column Type Role Label
adresse_id character code
alder_haend integer value
alder_ult integer value
bank_statsb character code
civst character code
cprtjek character value
cprtype character value
foedreg_kode character code
foed_dag date date
foed_land character code
ie_type character code
koen integer code
kom character code
opr_land character code
referencetid date date
reg character code
statsb character code
version character value
  • adresse_id: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • alder_haend: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • alder_ult: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • bank_statsb: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • cprtjek: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • cprtype: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • foedreg_kode: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • foed_dag: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • foed_land: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • ie_type: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • opr_land: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • referencetid: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • statsb: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • version: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.

No published source gives a data type for 22 of these 22 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (5)
Code system Values
civst U Ugift, G Gift (+ separeret), F Skilt, E Enke/Enkemand, P Registreret partnerskab, O Ophævet partnerskab, L Længstlevende af 2 partnere, D Død, 9 Uoplyst civilstand
ie_type 1 Dansk, 2 Indvandrere, 3 Efterkommere, 9 Uoplyst
koen 1 Mand, 2 Kvinde, 9 Uoplyst
kom Not listed here - see DST’s classification
reg 0 Uoplyst, 81 Nordjylland, 82 Midtjylland, 83 Syddanmark, 84 Hovedstaden, 85 Sjælland
  • civst: Codes P, O and L came in with the registered-partnership act of 1 October 1989; before that the set was smaller. Registered partnerships could no longer be entered into from 15 June 2012.
  • ie_type: DST’s current high-quality page for IE_TYPE states that the variable has no value set. The codes here come from the older TIMES3 archive page, which does publish them.
  • koen: DST’s classification KOEN_V1_1980 also defines 9 for not stated, which a delivery may not contain but a value set should. Sex is taken from the tenth digit of the CPR number: even is female, odd is male.
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.
  • reg: Do not confuse these with AMT, the pre-2007 counties, which has 16 codes in the ranges 11-14, 21-24, 31-37 and 88. Different geography, different era.

Where these values come from:

VNDS_ud - emigrations (2005 onwards)

Column Type Role Label
pnr character join key Personal identifier
haend_dato date date Date of emigration
udv_land character code Country emigration to
udvmd character date Month of emigration
All other columns (18)
Column Type Role Label
adresse_id character code
alder_haend integer value
alder_ult integer value
bank_statsb character code
civst character code
cprtjek character value
cprtype character value
foedreg_kode character code
foed_dag date date
foed_land character code
ie_type character code
koen integer code
kom character code
opr_land character code
referencetid date date
reg character code
statsb character code
version character value
  • adresse_id: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • alder_haend: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • alder_ult: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • bank_statsb: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • cprtjek: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • cprtype: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • foedreg_kode: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • foed_dag: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • foed_land: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • ie_type: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • opr_land: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • referencetid: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • statsb: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.
  • version: DST’s variable list gives this column no label, so the schema records the name only. Its meaning has not been sourced.

No published source gives a data type for 22 of these 22 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (5)
Code system Values
civst U Ugift, G Gift (+ separeret), F Skilt, E Enke/Enkemand, P Registreret partnerskab, O Ophævet partnerskab, L Længstlevende af 2 partnere, D Død, 9 Uoplyst civilstand
ie_type 1 Dansk, 2 Indvandrere, 3 Efterkommere, 9 Uoplyst
koen 1 Mand, 2 Kvinde, 9 Uoplyst
kom Not listed here - see DST’s classification
reg 0 Uoplyst, 81 Nordjylland, 82 Midtjylland, 83 Syddanmark, 84 Hovedstaden, 85 Sjælland
  • civst: Codes P, O and L came in with the registered-partnership act of 1 October 1989; before that the set was smaller. Registered partnerships could no longer be entered into from 15 June 2012.
  • ie_type: DST’s current high-quality page for IE_TYPE states that the variable has no value set. The codes here come from the older TIMES3 archive page, which does publish them.
  • koen: DST’s classification KOEN_V1_1980 also defines 9 for not stated, which a delivery may not contain but a value set should. Sex is taken from the tenth digit of the CPR number: even is female, odd is male.
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.
  • reg: Do not confuse these with AMT, the pre-2007 counties, which has 16 codes in the ranges 11-14, 21-24, 31-37 and 88. Different geography, different era.

Where these values come from:

2. LPR2 - Somatic (up to March 2019)

The register itself is owned by the Danish Health Data Authority, whose documentation covers what is reported and how it changed over time: Landspatientregisteret →.

Join: lpr_adm LEFT JOIN lpr_diag ON recnum.

lpr_adm - Contacts

Column Type Role Label Years
recnum character join key Contact identifier 1977 to 2019
pnr character identifier Personal identifier 1977 to 2019
d_inddto date date Date of admission 1977 to 2019
d_uddto date date Date of discharge 1977 to 2019
c_pattype character code Patient type 1977 to 2019
c_spec character code Specialty 1977 to 2019
c_adiag character code Action diagnosis 1977 to 2019
c_indm character code Admission mode 1977 to 2019
year integer date Register year
All other columns (43)
Column Type Role Label Years
c_sgh character code Hospital 1977 to 2019
c_afd character code Department 1977 to 2019
v_alder numeric value Age at the start of the contact 1977 to 2019
c_udm character code Discharge mode 1987 to 2019
c_henm character code Referral mode 1987 to 2019
c_kontaars character code Reason for the contact 1987 to 2019
c_bopamt character code County of residence 1977 to 2004
c_amt character code County 2005 to 2019
v_sengdage numeric value Bed days 1994 to 2019
v_behdage numeric value Treatment days 1977 to 2019
c_sex character code Sex 1977 to 2019
cprtjek character code CPR-tjek 1977 to 2019
cprtype character code CPR-type 1977 to 2019
c_andenbeh character code 1977 to 1986
c_blok character code Inddeling af speciale i blokke 1994 to 2019
c_eakt character code Ulykkeskode, aktivitet 1987 to 2003
c_emek character code 1987 to 2003
c_emodpart character code Ulykkeskode, modpart 1994 to 2003
c_epart character code Ulykkeskode, egenpart 1994 to 2003
c_ested character code Ulykkeskode, sted 1987 to 2003
c_etraf character code Ulykkeskode, trafikal 1987 to 2003
c_hafd character code Henvisende afdeling 2004 to 2019
c_hsgh character code Henvisende sygehus 2004 to 2019
c_indform character code 1977 to 1986
c_indfra character code 1977 to 1986
c_kom character code Kommune 1977 to 2019
c_nyafd character code 2005 to 2019
c_senstat character code 1977 to 1986
c_sghamt character code Sygehusamt 1977 to 2019
c_udtil character code 1977 to 1986
c_ulykke character code 1977 to 1986
d_ebhdto date date Data for endelig behandling (Variabel udgået efter 31.12.2003) 1996 to 2019
d_fusdto date date Dato for forundersøgelse (Variabel udgået efter 31.12.2003) 1996 to 2019
d_hendto date date Henvisningsdato 1977 to 2019
d_opdatdto date date Intern dato for opdatering af kontakten 2005 to 2019
k_afd character code Afdelingskode 2005 to 2019
leverancedato date date 1977 to 2019
version character code Version 1977 to 2019
v_alddg numeric value Alder i dage ved kontaktens start 2001 to 2019
v_aldmdr numeric value Alder i måneder ved kontaktens start 2001 to 2019
v_indminut numeric value Indlæggelsminut 1994 to 2019
v_indtime numeric date Indlæggelsestidspunkt 1977 to 2019
v_udtime numeric value Udskrivningstime 1994 to 2019
  • c_udm: Starts in 1987, ten years after the register itself.
  • c_bopamt: Ends with the counties themselves: the 2007 local government reform is already visible here in 2004/2005, where c_bopamt stops and c_amt starts. Neither covers the whole register, so a geographic analysis spanning that point needs both.
  • v_sengdage: Starts in 1994. Before that, compute the stay from d_inddto and d_uddto instead.
  • v_behdage: Ends in 2001.
  • c_sex: The coding changes in 2005, from 1/2 to M/K. Prefer koen from BEF for a study variable.

No published source gives a data type for 20 of these 52 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: recnum.

Joins to other registers:

  • recnum joins to LPR_DIAG (one-to-many).
Value sets for the coded columns (21)
Code system Values
pattype 0 Heldoegnspatient (to 2001), Indlagt patient (2002-), 1 Dagpatient (to 1986), Deldoegnspatient (1987-2001), 2 Natpatient (to 1986), Ambulant patient (1987-), 3 Skadestuepatient
icd10_sks Not listed here - see DST’s classification
indm 1 Akut, 2 Ikke akut, 9 Uoplyst
c_udm 1 Udskrevet/afsluttet til alment praktiserende læge, 2 Udskrevet/afsluttet til praktiserende speciallæge, 3 Udskrevet/afsluttet til eget heldøgnsafsnit eller eget deldøgnsafsnit, 4 Ingen lægelig opfølgning (må kun anvendes for psykiatriske afdelinger), 5 Udskrevet/afsluttet til andet heldøgnsafsnit eller andet deldøgnsafsnit, 6 Udskrevet/afsluttet til ambulatorium, 7 Udeblevet (kun ambulante patienter), 8 Død, 9 Uoplyst, A Andet, B Udskrevet/afsluttet til eget ambulatorium, C Udskrevet/afsluttet til andet ambulatorium, E Behandling i udlandet (hvor sygehus beslutter behandling i udlandet), F Afsluttet til sygehusafsnit, G Afsluttet til sygehusafsnit, venteforløb, K Afsluttet til sygehusafsnit (hjemmet), L Afsluttet til sygehusafsnit, venteforløb (hjemmet)
c_henm 0 Ingen henvisning, 1 Henvist fra alment praktiserende læge, 2 Henvist fra praktiserende speciallæge, 3 Henvist fra eget heldøgnsafsnit eller eget deldøgnsafsnit, 5 Henvist fra andet heldøgnsafsnit eller andet deldøgnsafsnit, 6 Henvist fra skadestue eller ambulatorium, 8 Herfødt, 9 Uoplyst, A Andet, B Eget ambulatorium, C Andet ambulatorium, D Skadestue, E Udlandet (kun direkte henvisninger), F Henvist fra sygehusafsnit, G Henvist fra sygehusafsnit, venteforløb
c_kontaars 1 Sygdom og tilstand uden direkte sammenhæng med udefra påført læsion, 2 Ulykke, 3 Voldshandling, 4 Selvmord/selvmordsforsøg, 5 Senfølge, 6 Komplet skaderegistrering foretages på efterfølgende kontakt, 7 Komplet skaderegistrering foretaget på tidligere kontakt, 8 Andet, 9 Uoplyst
sex_lpr 1 Mand (to 2004), 2 Kvinde (to 2004), M Mand (2005-), K Kvinde (2005-)
c_andenbeh 0 Ja, eget ambulatorium, 1 Ja, andet ambulatorium, eget sygehus, 2 Ja, andet ambulatorium, andet sygehus, 3 Ja, egen læge, 6 Ja, anden, 7 Ingen, 8 Død, 9 Uoplyst
c_blok 1 Medicinsk blok, 2 Kirurgisk blok, 5 Psykiatrisk blok, 6 Laboratorie blok, 8 Øvrige specialer, 9 Andre specialer, 99 Uden for specialer
c_eakt 1 Idræt, sport og motion, 2 Leg, hobby og and fritidsvirksomhed, 3 Erhvervsarbejde, 4 Vitalaktivitet, 5 Ulønnet arbejde, 8 Anden aktivitet, 9 Ikke specificeret aktivitet
c_emek 0 Slag, stød grundet fald på samme niveau, 1 Slag, stød grundet fald på trappe eller til lavere niveau, 2 Slag, stød grundet kontakt med anden genstand, person eller dyr, 3 Klemning, snit eller stik, 4 Fremmedlegeme, 5 Kvælning, 6 Kemisk påvirkning, 7 Termisk, elektrisk eller strålingspåvirkning, 8 Akut overbelastning af legeme eler legemesdel, 9 Anden og ukendt skadesmekanisme
c_emodpart 0 Ingen modpart, 1 Til fods, 2 Cykel, 3 Knallert, 4 Motorcykel eller scooter, 5 Personbil, 6 Varevogn, 7 Lastbil, bus, m.m., 8 Anden transportform, modpart, 9 Ikke specificeret transportform, modpart
c_epart 1 Til fods, 2 Cykel, 3 Knallert, 4 Motorcykel eller scooter, 5 Personbil, 6 Varevogn, 7 Lastbil, bus, m.m., 8 Anden transportform, tilskadekomne, 9 Ikke specificeret transportform, tilskadekomne
c_ested 0 Trafikområde, 1 Boligområde, 2 Produktions- og værkstedsområde, 3 Butiks- handels- og serviceområde, 4 Skole, offentlig administrations- og institutionsområde, 5 Idræts- og sportsområdet, 6 Forlystelses- og parkområdet, 7 Fri natur, 8 Hav, sø og vådområder, 9 Uoplyst
c_etraf 1 Færdselsuheld, 2 Ikke færdselsuheld
c_indform 0 Akut indlæggelse, 1 Indkaldt via forambulatorium, 2 Indkaldt via andet ambulatorium, 3 Anden indkaldelse, 4 Genindkaldt, 5 Indkaldt via koordineret forundersøgelse, 8 Herfødt, 9 Uoplyst
c_indfra 0 Hjemmet, 1 Hjemmet ekskl. døgnistitution, 2 Psykiatrisk hospital/sygehusafdeling, 3 Psykiatrisk dag/nathospital, 4 Somatisk afdeling, 5 Plejehjem/institution, 6 Andet, 8 Født her, 9 Uoplyst, A Andet
c_senstat 0 Ja, samme afdeling, 1 Ja, anden afdeling, 2 Ja, andet sygehus, 3 Ja, alderdoms- eller plejehjem, 5 Ja, rekreationshjem, 6 Ja, andre institutioner, 7 Ingen, 8 Død, 9 Uoplyst
c_udtil 0 Hjemmet, 1 Hjemmet ekskl. døgnistitution, 2 Psykiatrisk hospital/sygehusafdeling, 3 Psykiatrisk dag/nathospital, 4 Somatisk afdeling, 5 Plejehjem/institution, 6 Andet, 8 Død, 9 Uoplyst, A Andet
c_ulykke 0 Nej, 1 Ja, trafikulykke, 2 Ja, arbejdsulykke, 3 Ja, idrætsulykke, 4 Ja, hjemmeulykke, 5 Ja, anden ulykke, 6 Uoplyst, 7 Uoplyst
icd8 Not listed here - see DST’s classification
  • pattype: There are four codes, not six, and three of them changed meaning. Code 1 was Dagpatient until 1986 and Deldoegnspatient from 1987, and then stops entirely at the end of 2001. Code 2 was Natpatient until 1986 and Ambulant from 1987. Code 0 was Heldoegnspatient until 2001 and Indlagt patient from 2002. The register only started using 1, 2 and 3 in 1994, so before that essentially every contact is 0. Code 3 was discontinued at the end of 2013, and from 2014 an emergency-room visit arrives as 2 with an acute admission mode in c_indm. Reading 2 as outpatient across the whole register therefore mislabels night patients before 1987 and emergency visits after 2013.
  • icd10_sks: The D prefix is a Danish addition, not part of the WHO code. Matching WHO codes directly against LPR without allowing for it returns nothing. Do not carry the habit across to the cause-of-death registers: they hold the plain code, so stripping a D there removes the first real character instead.
  • indm: From 2014 this is what separates an emergency-room visit from an ordinary outpatient one, because c_pattype code 3 was discontinued and both arrive as 2. Code 9 (Uoplyst) stops at the end of 2003, so a missing value after that is genuinely missing rather than coded as unknown.
  • c_udm: Only codes 1, 8 and 9 reach back to 1987, and 9 stops in 2003. Discharge to another hospital unit is the trap: it was 3, 5, B or C until 2003 or 2004 and becomes F, G, K or L from 2004 onwards. Counting “discharged onwards to hospital” across the whole register therefore needs both sets, and either set alone gives a series with a hole in it. Codes 2, 4, 7 and A only begin in 1995, E in 2002, and K and L in 2006.
  • c_henm: Only four codes cover the whole register: 0, 1, 2 and 8. Everything else has a window. Codes 3, 5, 9, B, C and D stop at the end of 2003 and 6 stops at the end of 1998, while F and G only begin in 2004, A in 1995 and E in 2002. The end of 2003 is a break: referrals from a hospital unit were coded 3, 5, B, C or D before it and F or G after it. Counting any of those across the whole period gives a number that changes for administrative reasons alone.
  • c_kontaars: Code 4 was Selvtilføjet skade until the end of 1993 and Selvmord/selvmordsforsøg from 1994. Those are not the same population: self-inflicted injury is wider than an attempt at suicide, so a series that spans 1994 changes definition rather than changing level. Codes 5 and 9 stop at the end of 2013. Code 7 only starts in 2011 and code 6 only in 2014, so neither says anything about earlier contacts.
  • sex_lpr: The coding changed at the start of 2005: 1/2 until the end of 2004, M/K from 2005. A study spanning that year that filters on c_sex == "2" keeps only the women seen before 2005 and silently drops the rest, with no error and no empty result to warn you. Take sex from BEF instead, where it is koen coded 1/2 throughout, unless you specifically need what the hospital recorded.
  • c_andenbeh: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.1986.
  • c_eakt: 2 of the 7 codes were REUSED with a different meaning, so the same number does not mean the same thing across the register. The lookup above gives the current meaning; the periods block gives both. Code 1: arbejdsulykke, then idræt, sport og motion from 01.01.1995. Code 2: ikke arbejdsulykke, then leg, hobby og and fritidsvirksomhed from 01.01.1995. Every code in this variable stops by 31.12.2003, so it says nothing about later contacts.
  • c_emek: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.2003.
  • c_emodpart: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.2003.
  • c_epart: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.2003.
  • c_ested: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.2003.
  • c_etraf: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.2003.
  • c_indform: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.1986.
  • c_indfra: 4 of the 10 codes were REUSED with a different meaning, so the same number does not mean the same thing across the register. The lookup above gives the current meaning; the periods block gives both. Code 1: anden afdeling, then hjemmet ekskl. døgnistitution from 01.01.1995. Code 2: andet sygehus, then psykiatrisk hospital/sygehusafdeling from 01.01.1995. Code 3: alderdoms- eller plejehjem, then psykiatrisk dag/nathospital from 01.01.1995. Code 5: skadestue, then plejehjem/institution from 01.01.1995. Every code in this variable stops by 31.12.2000, so it says nothing about later contacts.
  • c_senstat: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.1986.
  • c_udtil: 4 of the 10 codes were REUSED with a different meaning, so the same number does not mean the same thing across the register. The lookup above gives the current meaning; the periods block gives both. Code 1: anden afdeling, then hjemmet ekskl. døgnistitution from 01.01.1995. Code 2: andet sygehus, then psykiatrisk hospital/sygehusafdeling from 01.01.1995. Code 3: alderdoms- eller plejehjem, then psykiatrisk dag/nathospital from 01.01.1995. Code 5: rekreationshjem, then plejehjem/institution from 01.01.1995. Every code in this variable stops by 31.12.2000, so it says nothing about later contacts.
  • c_ulykke: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.1986.
  • icd8: A study whose period starts before 1994 is reading two classifications out of one column. ICD-10 codes match nothing in the early years, and the usual substr(c_diag, 2, 4) returns a meaningless fragment of an ICD-8 code rather than failing, so nothing tells you it went wrong.

Where these values come from:

Worth knowing:

  • recnum: The key every other LPR2 dataset joins on. It identifies a contact, not a person.
  • d_inddto: Use this as the contact date. It is the admission date, so for an outpatient course it is the date the course started, not the date of a particular visit.
  • c_spec: DST publishes what each specialty code means in its department and specialty overview: https://www.dst.dk/da/Statistik/dokumentation/Times/moduldata-for-sociale-forhold–sundhedsvaesen–retsvaesen/spec (in Danish). The codes are not self-explanatory, so look them up rather than grouping on the digits.
  • c_adiag: A copy of the contact’s action diagnosis. Use lpr_diag instead: it holds every diagnosis on the contact, not only the action one.
  • c_indm: Used together with c_pattype to separate emergency-room contacts from ordinary outpatient ones after about 2014, see the LPR extraction chapter. Available for the register’s whole span, so a missing c_indm is an extract boundary rather than a coverage gap.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

lpr_diag - Diagnoses

Column Type Role Label Years
recnum character join key Contact identifier 1977 to 2019
c_diag character code Diagnosis code 1977 to 2019
c_diagtype character code Diagnosis type 1977 to 2019
c_tildiag character code Supplementary diagnosis 1995 to 2019
year integer date Register year
All other columns (3)
Column Type Role Label Years
c_diagmod character code Diagnosis modification 1977 to 1994
leverancedato date date 1977 to 2019
version character code Version 1977 to 2019

No published source gives a data type for 5 of these 8 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: recnum.

Joins to other registers:

  • recnum joins to LPR_ADM (many-to-one).
Value sets for the coded columns (4)
Code system Values
icd10_sks Not listed here - see DST’s classification
diagtype A Aktionsdiagnose, B Bidiagnose, G Grundmorbus, naar forskellig fra aktionsdiagnose, H Henvisningsdiagnose, M Midlertidig diagnose, kun for aabne somatisk ambulante besoeg, C Komplikation
c_diagmod 0 Ingen modifikation, 1 Obs. pro., 2 Ej befundet, 3 Sequelae, 4 Antea, 5 Recidivans, 6 Traktatus, 7 Operatus
icd8 Not listed here - see DST’s classification
  • icd10_sks: The D prefix is a Danish addition, not part of the WHO code. Matching WHO codes directly against LPR without allowing for it returns nothing. Do not carry the habit across to the cause-of-death registers: they hold the plain code, so stripping a D there removes the first real character instead.
  • diagtype: The guide long described this as an A/B/G column. There are six codes, and three of them stop: G runs 1995-2003 only, M 1998-2013 and C 2002-2013. A and B run the whole period, H from 1995. So a comorbidity definition built on G silently covers nine years and nothing else, and filtering to A/B/G drops referral diagnoses entirely. Which types to keep is a case definition, not a technicality: outcomes usually use A and B. Carry the type column into the extract so the definition can be varied later.
  • c_diagmod: Not every code covers the whole register. The periods block gives the window for each one; codes stop being used at 31.12.1986, 31.12.1994.
  • icd8: A study whose period starts before 1994 is reading two classifications out of one column. ICD-10 codes match nothing in the early years, and the usual substr(c_diag, 2, 4) returns a meaningless fragment of an ICD-8 code rather than failing, so nothing tells you it went wrong.

Where these values come from:

Worth knowing:

  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

3. LPR2 - Psychiatric (1995 – March 2019)

Psychiatric contacts before March 2019 are in separate registers from somatic LPR2. From March 2019, LPR3 covers both in one table.

Before 1995: inpatients only, and ICD-8

The Danish Psychiatric Central Register is electronic from 1969, but covers only inpatients until 1995 (outpatient visits were added from 1995), and diagnoses before 1994 are coded in ICD-8 (numeric codes, e.g. 290-315, where 290 covers dementia) - not ICD-10 F-codes. These older data are normally not part of the standard extract and are requested separately, via Rigsarkivet or NCRR, Aarhus University. If your study covers that period, you have to map ICD-8 to your F-code groups yourself.

If you forget to query the psychiatric registers for the period 1995–2019, you miss all dementia diagnoses (F00–F03) recorded at geriatric psychiatry outpatient clinics and memory clinics. Those patients will appear dementia-free and remain in the cohort as false negatives.

t_psyk_adm - Psychiatric contacts

The key and person columns may be renamed in your delivery. DST’s variable list gives both psychiatric tables RECNUM and PNR, the same names the somatic registers use. Several deliveries hand them over renamed: DARTER has k_recnum and v_cpr here, and v_recnum in the diagnosis table, so one key ends up with three names. That is data processing, not the register. Run colnames() first, and rename to recnum and pnr if yours differ:

library(fastreg) # read_register()
library(dplyr) # %>%, rename_with(), rename()

psyk_adm <- read_register("t_psyk_adm") %>%
  rename_with(tolower) %>%
  rename(pnr = v_cpr, recnum = k_recnum)
Column Type Role Label
pnr character join key Personal identifier
recnum character join key Contact identifier
c_pattype character code Contact type
c_adiag character code Primary diagnosis
d_inddto date date Admission date
d_uddto date date Discharge date
All other columns (32)
Column Type Role Label
c_indm character code Admission mode
c_udm character code Discharge mode
c_sgh character code Hospital
c_afd character code Department
c_spec character code Specialty
v_indtime integer value Admission hour
v_indminut integer value Admission minute
v_udtime integer value Discharge hour
cprtjek character code CPR-tjek
cprtype character code CPR-type
c_amt character code AMT
c_blok character code Inddeling af speciale i blokke
c_hafd character code Henvisende afdeling
c_henm character code Henvisningsmåde
c_hsgh character code Henvisende sygehus
c_kom character code Kommune
c_kontaars character code Kontaktårsag
c_nyafd character code
c_sex character code Køn
c_sghamt character code Sygehusamt
d_ebhdto date date Data for endelig behandling (Variabel udgået efter 31.12.2003)
d_fusdto date date Dato for forundersøgelse (Variabel udgået efter 31.12.2003)
d_hendto date date Henvisningsdato
d_opdatdto date date Intern dato for opdatering af kontakten
k_afd character code Afdelingskode
leverancedato date date
version character code Version
v_alddg numeric value Alder i dage ved kontaktens start
v_alder numeric value Alder i år ved kontaktens start
v_aldmdr numeric value Alder i måneder ved kontaktens start
v_behdage numeric value Behandlingsdage (Variabel udgået efter 31.12.2001)
v_sengdage numeric value Sengedage

No published source gives a data type for 6 of these 38 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: recnum.

Joins to other registers:

  • recnum joins to T_PSYK_DIAG (one-to-many).
Value sets for the coded columns (8)
Code system Values
pattype 0 Heldoegnspatient (to 2001), Indlagt patient (2002-), 1 Dagpatient (to 1986), Deldoegnspatient (1987-2001), 2 Natpatient (to 1986), Ambulant patient (1987-), 3 Skadestuepatient
icd10_sks Not listed here - see DST’s classification
indm 1 Akut, 2 Ikke akut, 9 Uoplyst
c_udm 1 Udskrevet/afsluttet til alment praktiserende læge, 2 Udskrevet/afsluttet til praktiserende speciallæge, 3 Udskrevet/afsluttet til eget heldøgnsafsnit eller eget deldøgnsafsnit, 4 Ingen lægelig opfølgning (må kun anvendes for psykiatriske afdelinger), 5 Udskrevet/afsluttet til andet heldøgnsafsnit eller andet deldøgnsafsnit, 6 Udskrevet/afsluttet til ambulatorium, 7 Udeblevet (kun ambulante patienter), 8 Død, 9 Uoplyst, A Andet, B Udskrevet/afsluttet til eget ambulatorium, C Udskrevet/afsluttet til andet ambulatorium, E Behandling i udlandet (hvor sygehus beslutter behandling i udlandet), F Afsluttet til sygehusafsnit, G Afsluttet til sygehusafsnit, venteforløb, K Afsluttet til sygehusafsnit (hjemmet), L Afsluttet til sygehusafsnit, venteforløb (hjemmet)
c_blok 1 Medicinsk blok, 2 Kirurgisk blok, 5 Psykiatrisk blok, 6 Laboratorie blok, 8 Øvrige specialer, 9 Andre specialer, 99 Uden for specialer
c_henm 0 Ingen henvisning, 1 Henvist fra alment praktiserende læge, 2 Henvist fra praktiserende speciallæge, 3 Henvist fra eget heldøgnsafsnit eller eget deldøgnsafsnit, 5 Henvist fra andet heldøgnsafsnit eller andet deldøgnsafsnit, 6 Henvist fra skadestue eller ambulatorium, 8 Herfødt, 9 Uoplyst, A Andet, B Eget ambulatorium, C Andet ambulatorium, D Skadestue, E Udlandet (kun direkte henvisninger), F Henvist fra sygehusafsnit, G Henvist fra sygehusafsnit, venteforløb
c_kontaars 1 Sygdom og tilstand uden direkte sammenhæng med udefra påført læsion, 2 Ulykke, 3 Voldshandling, 4 Selvmord/selvmordsforsøg, 5 Senfølge, 6 Komplet skaderegistrering foretages på efterfølgende kontakt, 7 Komplet skaderegistrering foretaget på tidligere kontakt, 8 Andet, 9 Uoplyst
sex_lpr 1 Mand (to 2004), 2 Kvinde (to 2004), M Mand (2005-), K Kvinde (2005-)
  • pattype: There are four codes, not six, and three of them changed meaning. Code 1 was Dagpatient until 1986 and Deldoegnspatient from 1987, and then stops entirely at the end of 2001. Code 2 was Natpatient until 1986 and Ambulant from 1987. Code 0 was Heldoegnspatient until 2001 and Indlagt patient from 2002. The register only started using 1, 2 and 3 in 1994, so before that essentially every contact is 0. Code 3 was discontinued at the end of 2013, and from 2014 an emergency-room visit arrives as 2 with an acute admission mode in c_indm. Reading 2 as outpatient across the whole register therefore mislabels night patients before 1987 and emergency visits after 2013.
  • icd10_sks: The D prefix is a Danish addition, not part of the WHO code. Matching WHO codes directly against LPR without allowing for it returns nothing. Do not carry the habit across to the cause-of-death registers: they hold the plain code, so stripping a D there removes the first real character instead.
  • indm: From 2014 this is what separates an emergency-room visit from an ordinary outpatient one, because c_pattype code 3 was discontinued and both arrive as 2. Code 9 (Uoplyst) stops at the end of 2003, so a missing value after that is genuinely missing rather than coded as unknown.
  • c_udm: Only codes 1, 8 and 9 reach back to 1987, and 9 stops in 2003. Discharge to another hospital unit is the trap: it was 3, 5, B or C until 2003 or 2004 and becomes F, G, K or L from 2004 onwards. Counting “discharged onwards to hospital” across the whole register therefore needs both sets, and either set alone gives a series with a hole in it. Codes 2, 4, 7 and A only begin in 1995, E in 2002, and K and L in 2006.
  • c_henm: Only four codes cover the whole register: 0, 1, 2 and 8. Everything else has a window. Codes 3, 5, 9, B, C and D stop at the end of 2003 and 6 stops at the end of 1998, while F and G only begin in 2004, A in 1995 and E in 2002. The end of 2003 is a break: referrals from a hospital unit were coded 3, 5, B, C or D before it and F or G after it. Counting any of those across the whole period gives a number that changes for administrative reasons alone.
  • c_kontaars: Code 4 was Selvtilføjet skade until the end of 1993 and Selvmord/selvmordsforsøg from 1994. Those are not the same population: self-inflicted injury is wider than an attempt at suicide, so a series that spans 1994 changes definition rather than changing level. Codes 5 and 9 stop at the end of 2013. Code 7 only starts in 2011 and code 6 only in 2014, so neither says anything about earlier contacts.
  • sex_lpr: The coding changed at the start of 2005: 1/2 until the end of 2004, M/K from 2005. A study spanning that year that filters on c_sex == "2" keeps only the women seen before 2005 and silently drops the rest, with no error and no empty result to warn you. Take sex from BEF instead, where it is koen coded 1/2 throughout, unless you specifically need what the hospital recorded.

Where these values come from:

Worth knowing:

  • pnr: DST’s variable list calls this column PNR. Some deliveries rename it: some deliveries hand it over as v_cpr. The name is a product of the data processing, not of the register, so check your own columns and rename.
  • recnum: DST’s variable list calls this column RECNUM, the same name the somatic lpr_adm uses. Some deliveries rename it, and not consistently: the contact table can arrive as k_recnum and the diagnosis table as v_recnum. Rename both to recnum before joining.
  • c_pattype: Present here even where the somatic lpr_adm extract leaves it out, so the psychiatric side of a study can be classified when the somatic side cannot. Do not assume symmetry between the two extracts.

t_psyk_diag - Psychiatric diagnoses

psyk_diag <- read_register("t_psyk_diag") %>%
  rename_with(tolower) %>%
  rename(recnum = v_recnum)
Column Type Role Label
recnum character join key Contact identifier
c_diag character code Diagnosis code
c_diagtype character code Diagnosis type
c_tildiag character code Supplementary diagnosis
All other columns (2)
Column Type Role Label
leverancedato date date
version character code Version

No published source gives a data type for 2 of these 6 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: recnum.

Joins to other registers:

  • recnum joins to T_PSYK_ADM (many-to-one).
Value sets for the coded columns (2)
Code system Values
icd10_sks Not listed here - see DST’s classification
diagtype A Aktionsdiagnose, B Bidiagnose, G Grundmorbus, naar forskellig fra aktionsdiagnose, H Henvisningsdiagnose, M Midlertidig diagnose, kun for aabne somatisk ambulante besoeg, C Komplikation
  • icd10_sks: The D prefix is a Danish addition, not part of the WHO code. Matching WHO codes directly against LPR without allowing for it returns nothing. Do not carry the habit across to the cause-of-death registers: they hold the plain code, so stripping a D there removes the first real character instead.
  • diagtype: The guide long described this as an A/B/G column. There are six codes, and three of them stop: G runs 1995-2003 only, M 1998-2013 and C 2002-2013. A and B run the whole period, H from 1995. So a comorbidity definition built on G silently covers nine years and nothing else, and filtering to A/B/G drops referral diagnoses entirely. Which types to keep is a case definition, not a technicality: outcomes usually use A and B. Carry the type column into the extract so the definition can be varied later.

Where these values come from:

Worth knowing:

  • recnum: DST’s variable list calls this column RECNUM. Some deliveries rename it, and not consistently: this table can arrive as v_recnum while the contact table gets k_recnum. One key, three names. Check and rename to recnum.

4. LPR3 (March 2019 and onwards)

LPR3 covers both somatic and psychiatric contacts in one table. Join: lpr_a_kontakt LEFT JOIN lpr_a_diagnose ON dw_ek_kontakt.

The “a” in lpr_a_diagnose does not mean A-type diagnoses. It refers to the analysis model designation for the LPR3 series (LPR_A, introduced 2025). The table contains all types, A, B and G, so you still need to filter on diag_kode_type.

lpr_a_kontakt - Contacts

Column Type Role Label
dw_ek_kontakt character join key Contact identifier
dw_ek_forloeb character code Course identifier
pnr character identifier Personal identifier
kont_starttidspunkt datetime date Contact start
kont_sluttidspunkt datetime date Contact end
kont_type character code Contact type
lprindberetningssystem character code Reporting system
adiag character code Primary diagnosis
prioritet character code Priority
kont_ans_hovedspec character code Responsible main specialty
year integer date Register year
All other columns (43)
Column Type Role Label
dw_sk_sygehusophold character code Hospital stay identifier
dw_ek_helbredsforloeb character code Health course identifier
dw_ek_borger character code Citizen identifier
adiag_tekst character value Primary diagnosis, text
kont_type_tekst character value Contact type, text
kont_patient_type character code Patient type
kont_patient_type_tekst character value Patient type, text
prioritet_tekst character value Priority, text
kont_aarsag character code Reason for the contact
kont_aarsag_tekst character value Reason for the contact, text
kont_henv_aarsag character code Referral reason
kont_henv_aarsag_tekst character value Referral reason, text
kont_henv_maade character code Referral mode
kont_henv_maade_tekst character value Referral mode, text
kont_henv_instans character code Referring body
kont_henv_tidspunkt datetime date Referral time
kont_indb_tidspunkt datetime date Reporting time
beh_starttidspunkt datetime date Treatment start
flag_kont_afsluttet numeric code Contact closed flag
kont_ans character code Responsible unit
kont_ans_inst character code Responsible institution
kont_ans_hovedspec_shak character code Responsible main specialty, SHAK
kont_ans_geo_reg character code Region of the treating unit, geographic
kont_ans_geo_reg_tekst character value Region of the treating unit, text
kont_ans_org_reg character code Region of the treating unit, organisational
kont_ans_org_reg_tekst character value Organisational region, text
kont_inst_ejertype character code Institution ownership type
kont_fir_kode character code Company code
kont_fir_tekst character value Company, text
kont_fritvalg character code Free choice of hospital
kont_fritvalg_tekst character value Free choice, text
kont_lpr_entity_id character code LPR entity identifier
borger_koen character code Sex
borger_foedselsdato date date Date of birth
borger_doedsdato date date Date of death
borger_alder_aar_ind numeric value Age in years at contact start
borger_alder_aar_ud numeric value Age in years at contact end
borger_bo_kom character code Municipality of residence
borger_bo_kom_tekst character value Municipality of residence, text
borger_bo_reg character code Region of residence
borger_bo_reg_tekst character value Region of residence, text
cprtjek character code CPR check
cprtype character code CPR type
  • dw_sk_sygehusophold: A stay can gather several contacts. Counting rows here is not the same as counting admissions.
  • dw_ek_borger: An internal person key. Use pnr for joins to other registers; this one does not travel outside LPR3.
  • kont_indb_tidspunkt: When the contact was reported, not when it happened. Recent months look incomplete because reporting lags.
  • flag_kont_afsluttet: An open contact has no end time yet, so durations computed near the end of the data are wrong rather than missing.
  • borger_koen: Sex as recorded on the contact, as text rather than a number. No published source gives its value set, so this schema records none. Checked without success: Sundhedsdatastyrelsen’s Vejledning til LPR3_F, which documents these very research tables; the LPR3 reporting guidance; esundhed’s LPR documentation, which covers LPR2 only; and DST’s variable list, which names the column but gives neither label nor values. Treat this as settled rather than as something still to look up. The neighbouring register is no guide either: LPR2’s c_sex switched from 1/2 to M/K in 2005, so both codings exist in the family and neither can be assumed here. If you need sex as a study variable, take koen from BEF, which is documented and stable; if you need what the hospital recorded, check what your own column contains before filtering on it.
  • borger_foedselsdato: A copy from CPR carried on the contact, so it only exists for people who had a hospital contact. BEF is the source to use for a study variable.
  • borger_doedsdato: A death date carried on the contact. It is not a death register: use DOD for mortality, or you only see people who had a hospital contact.

DST publishes no labels for 53 of these columns. Where the Label column is filled in anyway, it is this guide’s reading of the column name, not an official description.

Join key: dw_ek_kontakt.

Joins to other registers:

  • dw_ek_kontakt joins to LPR_A_DIAGNOSE (one-to-many).
Value sets for the coded columns (4)
Code system Values
kont_type Not listed here - see DST’s classification
icd10_sks Not listed here - see DST’s classification
reg 0 Uoplyst, 81 Nordjylland, 82 Midtjylland, 83 Syddanmark, 84 Hovedstaden, 85 Sjælland
kom Not listed here - see DST’s classification
  • kont_type: ALCA00 means physical attendance, which is the closest LPR3 gets to LPR2’s inpatient flag. It marks attendance, not admission, so a study that treats it as “was admitted” will include outpatient visits. Check what your own delivery holds before filtering: single digits and SKS codes have been seen side by side in the same year, so kont_type == "ALCA00" can silently drop rows that are the same kind of contact recorded in the other form. Cross-tabulate it against lprindberetningssystem first. MiniPAS was the route private providers reported through, so the two forms are not only two notations, they are also two different parts of the health service.
  • icd10_sks: The D prefix is a Danish addition, not part of the WHO code. Matching WHO codes directly against LPR without allowing for it returns nothing. Do not carry the habit across to the cause-of-death registers: they hold the plain code, so stripping a D there removes the first real character instead.
  • reg: Do not confuse these with AMT, the pre-2007 counties, which has 16 codes in the ranges 11-14, 21-24, 31-37 and 88. Different geography, different era.
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.

Where these values come from:

Worth knowing:

  • dw_ek_kontakt: The key the diagnosis and procedure tables join on.
  • dw_ek_forloeb: One level above the contact: a course of treatment can span several contacts, so joining on this is not the same as joining on the contact.
  • kont_starttidspunkt: A datetime, not a date. as.Date() it before comparing with an index date.
  • lprindberetningssystem: Filter to “LPR3”. The table reaches back to 2017, and the outpatient contacts from before March 2019 are also in LPR2, so combining the two without this filter counts the same contact twice. The column also separates the two delivery formats, LPR_F and LPR_A.
  • adiag: The contact’s action diagnosis, repeated here so simple analyses need not join lpr_a_diagnose. Secondary diagnoses are only in the diagnosis table, so filtering on this column alone misses them.
  • prioritet: The code ATA1 marks an acute contact. Together with the contact’s duration this is how LPR3 substitutes for LPR2’s c_pattype.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.
All confirmed columns in lpr_a_kontakt

pnr, dw_ek_kontakt, kont_starttidspunkt, kont_sluttidspunkt, kont_type, kont_type_tekst, kont_patient_type, kont_patient_type_tekst, kont_ans_hovedspec, kont_ans_hovedspec_shak, kont_ans_inst, kont_ans, kont_ans_geo_reg, kont_ans_geo_reg_tekst, kont_ans_org_reg, kont_ans_org_reg_tekst, borger_doedsdato, borger_foedselsdato, borger_koen, borger_alder_aar_ind, borger_alder_aar_ud, borger_bo_kom, borger_bo_kom_tekst, borger_bo_reg, borger_bo_reg_tekst, dw_sk_sygehusophold, dw_ek_helbredsforloeb, dw_ek_forloeb, dw_ek_borger, adiag, adiag_tekst, beh_starttidspunkt, flag_kont_afsluttet, kont_aarsag, kont_aarsag_tekst, kont_indb_tidspunkt, kont_fir_kode, kont_fir_tekst, kont_fritvalg, kont_fritvalg_tekst, kont_henv_aarsag, kont_henv_aarsag_tekst, kont_henv_instans, kont_henv_maade, kont_henv_maade_tekst, kont_henv_tidspunkt, kont_inst_ejertype, lprindberetningssystem, prioritet, prioritet_tekst, kont_lpr_entity_id, cprtjek, cprtype, year

DST’s variable list: LPR_A_KONTAKT → (in Danish). Look up the specialty code kont_ans_hovedspec in DST’s specialty/department overview → (in Danish).

lpr_a_diagnose - Diagnoses

Column Type Role Label
dw_ek_kontakt character join key Contact identifier
diag_kode character code Diagnosis code
diag_kode_type character code Diagnosis type
senere_afkraeftet character code Later retracted
diag_kode_tekst character value Diagnosis code, text
year integer date Register year
All other columns (6)
Column Type Role Label
diag_parent_kode character code Parent diagnosis code
lprindberetningssystem character code Reporting system
diag_kode_type_tekst character value Diagnosis type, text
diag_parent_kode_tekst character value Parent diagnosis code, text
diag_parent_kode_type character code Parent diagnosis type
diag_parent_kode_type_tekst character value Parent diagnosis type, text
  • lprindberetningssystem: Filter to “LPR3”: the table holds rows from two reporting formats, and not doing so duplicates rows.

DST publishes no labels for 11 of these columns. Where the Label column is filled in anyway, it is this guide’s reading of the column name, not an official description.

Join key: dw_ek_kontakt.

Joins to other registers:

  • dw_ek_kontakt joins to LPR_A_KONTAKT (many-to-one).
Value sets for the coded columns (2)
Code system Values
icd10_sks Not listed here - see DST’s classification
diagtype A Aktionsdiagnose, B Bidiagnose, G Grundmorbus, naar forskellig fra aktionsdiagnose, H Henvisningsdiagnose, M Midlertidig diagnose, kun for aabne somatisk ambulante besoeg, C Komplikation
  • icd10_sks: The D prefix is a Danish addition, not part of the WHO code. Matching WHO codes directly against LPR without allowing for it returns nothing. Do not carry the habit across to the cause-of-death registers: they hold the plain code, so stripping a D there removes the first real character instead.
  • diagtype: The guide long described this as an A/B/G column. There are six codes, and three of them stop: G runs 1995-2003 only, M 1998-2013 and C 2002-2013. A and B run the whole period, H from 1995. So a comorbidity definition built on G silently covers nine years and nothing else, and filtering to A/B/G drops referral diagnoses entirely. Which types to keep is a case definition, not a technicality: outcomes usually use A and B. Carry the type column into the extract so the definition can be varied later.

Where these values come from:

Worth knowing:

  • senere_afkraeftet: A diagnosis that was subsequently withdrawn. Keeping these counts conditions the patient turned out not to have.
  • diag_kode_tekst: The code spelled out. Convenient for reading, but do not group on it: the text can change between years while the code stays the same.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

Standard filter for senere_afkraeftet:

filter(is.na(senere_afkraeftet) | senere_afkraeftet != "Ja")

5. LPR - SKS procedure codes

SKS (Sundhedsvæsenets Klassifikations System - the Danish Health Classification System) is the Danish classification system for operations and procedures - equivalent to the NOMESCO codes used in the other Nordic countries. Bariatric surgery has e.g. codes KJDF10 (RYGB) and KJDF40 (sleeve gastrectomy). Look up codes in the SKS browser → (in Danish).

SKS codes are split across two registers depending on period. For full coverage both must be queried and the results bound together.

Neither procedure table holds pnr. It is fetched by joining to lpr_adm (LPR2) or lpr_a_kontakt (LPR3).

lpr_sksopr - LPR2 SKS procedures (up to 2018)

Location (DARTER): parquet-registers/lpr_sksopr

lpr_sksopr <- read_register("lpr_sksopr") %>%
  rename_with(tolower)
Column Type Role Label
recnum character join key Contact identifier
c_opr character code Procedure code
c_oprart character code Procedure type
c_osgh character code Hospital performing the procedure
c_tilopr character code Supplementary code
d_odto date date Procedure date
year integer date Register year
All other columns (5)
Column Type Role Label
c_oafd character code Procedurende afdeling (operation)
leverancedato date date
version character code Version
v_ominut numeric value Procedureminut (operation)
v_otime numeric value Proceduretime (operation)

No published source gives a data type for 8 of these 12 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: recnum.

Joins to other registers:

  • recnum joins to LPR_ADM (many-to-one).
Value sets for the coded columns (2)
Code system Values
sks Not listed here - see DST’s classification
oprart V Vigtigste operation i afsluttet kontakt, P Vigtigste operation i operativt indgreb, D Deloperation, + Tillaegskode
  • sks: The codes are hierarchical, so a prefix match selects a whole branch. That also makes it easy to select more than you meant: check how many characters your intended group actually needs before filtering with starts_with().
  • oprart: Counting rows in the procedure table counts add-on codes and sub-procedures as procedures. If you want one row per operation, filter to V or P first. All four codes run from 1996 with no breaks.

Where these values come from:

Worth knowing:

  • c_opr: The SKS procedure code. Surgical codes start with K.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

lpr_a_procregistrering - LPR3 SKS procedures (2019 and onwards)

The LPR3 procedure table. It sits alongside lpr_a_kontakt and lpr_a_diagnose, and joins to contacts on dw_ek_kontakt exactly like the diagnosis table does. Column names confirmed against DST’s variable list →.

Column Type Role Label
dw_ek_kontakt character join key Contact identifier
proc_kode character code Procedure code
proc_starttidspunkt datetime date Procedure start
proc_kode_type character code Procedure code type
proc_sluttidspunkt datetime date Procedure end
proc_parent_kode character code Parent procedure code
dw_ek_forloeb character code Course identifier
flag_proc_uden_kont character code Procedure without a contact
lprindberetningssystem character code Reporting system
All other columns (11)
Column Type Role Label
dw_ek_procedureregistrering character identifier Procedure registration identifier
dw_sk_sygehusophold character code Hospital stay identifier
proc_indb_tidspunkt datetime date Reporting time
proc_kode_tekst character value Procedure code, text
proc_kode_type_tekst character value Procedure code type, text
proc_parent_kode_tekst character value Parent procedure code, text
proc_parent_kode_type character code Parent procedure code type
proc_parent_kode_type_tekst character value Parent procedure code type, text
proc_lpr_entity_id character code LPR entity identifier
prod_enh character code Performing unit
prod_inst character code Performing institution
  • proc_indb_tidspunkt: When the procedure was reported, not when it happened. Recent months look incomplete because reporting lags.

DST publishes no labels for 20 of these columns. Where the Label column is filled in anyway, it is this guide’s reading of the column name, not an official description.

No published source gives a data type for 20 of these 20 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: dw_ek_kontakt.

Joins to other registers:

  • dw_ek_kontakt joins to LPR_A_KONTAKT (many-to-one).
Value sets for the coded columns (1)
Code system Values
sks Not listed here - see DST’s classification
  • sks: The codes are hierarchical, so a prefix match selects a whole branch. That also makes it easy to select more than you meant: check how many characters your intended group actually needs before filtering with starts_with().

Where these values come from:

Worth knowing:

  • dw_ek_kontakt: The key to lpr_a_kontakt, which is where pnr lives. This table carries no person identifier of its own.
  • proc_starttidspunkt: A datetime, not a date. as.Date() it before comparing with an index date.
  • proc_kode_type: “P” marks a procedure, “+” an add-on code. An add-on code modifies the procedure above it and is not a procedure in its own right, so counting all rows overcounts.
  • proc_parent_kode: LPR3 nests procedures the same way it nests diagnoses: an add-on code points at the procedure it belongs to.
  • dw_ek_forloeb: One level above the contact. Where dw_ek_kontakt is empty, this is the only route back to a person, and it reaches a whole course of treatment rather than a single contact.
  • flag_proc_uden_kont: Flags a procedure with no contact attached. Those rows cannot be joined to lpr_a_kontakt at all, so a plain inner join drops them silently.
  • lprindberetningssystem: Filter to “LPR3” when combining with LPR2, or contacts reported under both systems are counted twice.

There is no pnr here, as in every LPR procedure table: it identifies procedures, not people. Join to lpr_a_kontakt to get one.

A few rows have no contact to join to, and DST flags them for you in flag_proc_uden_kont. Count them before you drop them.

library(fastreg) # read_register()
library(dplyr) # filter, select, inner_join, mutate, collect

proc <- read_register("lpr_a_procregistrering") %>%
  rename_with(tolower) %>%
  filter(lprindberetningssystem == "LPR3") %>% # same duplicate filter as the contacts
  filter(proc_kode %in% !!MY_CODES) %>% # your SKS codes
  select(dw_ek_kontakt, proc_starttidspunkt)

surgery <- read_register("lpr_a_kontakt") %>%
  rename_with(tolower) %>%
  filter(lprindberetningssystem == "LPR3") %>%
  select(dw_ek_kontakt, pnr) %>% # pnr lives here
  inner_join(proc, by = "dw_ek_kontakt") %>%
  mutate(date_procedure = as.Date(proc_starttidspunkt)) %>%
  select(pnr, date_procedure) %>%
  collect()

lpr_sksube - SKS examinations and treatments (ZZ codes)

Examination and treatment codes (ZZ codes) live in lpr_sksube (LPR2), separate from the operation codes in lpr_sksopr above. Join like the other SKS tables, via recnum. The register is shaped exactly like lpr_sksopr.

Column Type Role Label
recnum character join key Contact identifier
c_opr character code Procedure code
d_odto date date Procedure date
year integer date Register year
All other columns (8)
Column Type Role Label
c_oprart character code Procedure type
c_osgh character code Hospital performing the procedure
c_tilopr character code Supplementary code
c_oafd character code Procedurende afdeling (undersøgelse & behandling)
leverancedato date date
version character code Version
v_ominut numeric value Procedureminut (undersøgelse & behandling)
v_otime numeric value Proceduretime (undersøgelse & behandling)

No published source gives a data type for 8 of these 12 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: recnum.

Joins to other registers:

  • recnum joins to LPR_ADM (many-to-one).
Value sets for the coded columns (2)
Code system Values
sks Not listed here - see DST’s classification
oprart V Vigtigste operation i afsluttet kontakt, P Vigtigste operation i operativt indgreb, D Deloperation, + Tillaegskode
  • sks: The codes are hierarchical, so a prefix match selects a whole branch. That also makes it easy to select more than you meant: check how many characters your intended group actually needs before filtering with starts_with().
  • oprart: Counting rows in the procedure table counts add-on codes and sub-procedures as procedures. If you want one row per operation, filter to V or P first. All four codes run from 1996 with no breaks.

Where these values come from:

Worth knowing:

  • c_opr: Check that you actually have this column. DST documents it for every year 1999-2019, but a delivery can arrive with only recnum, d_odto and year, which leaves no way to tell one procedure from another. Without it the table is unusable, and no filtering recovers it.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

Check that you actually have c_opr before planning around this register. DST documents it for every year 1999-2019, but at least one delivery contains only recnum, d_odto and year, which cannot tell one procedure from another. Run colnames() first.

Combination across the full period

See the code example: combination across the full period
# Replace [projectnumber] with your own project number
# With fastreg: read_register("registername") instead of open_dataset("path/to/registername/")

# SKS from LPR2 (up to 2018)
surg_lpr2 <- read_register("lpr_sksopr") %>%
  rename_with(tolower) %>%
  filter(toupper(c_opr) %in% !!SKS_CODES) %>%   # !! sends the local R vector to DuckDB
  left_join(
    read_register("lpr_adm") %>%
      rename_with(tolower) %>%
      select(recnum, pnr, d_inddto),
    by = "recnum"
  ) %>%
  select(pnr, surgery_date = d_odto, surgery_code = c_opr) %>%
  collect()

# SKS from LPR3 (2019 and onwards) - join via dw_ek_kontakt
surg_lpr3 <- read_register("lpr_a_procregistrering") %>%
  rename_with(tolower) %>%
  filter(toupper(proc_kode) %in% !!SKS_CODES) %>%   # !! sends the local R vector to DuckDB
  left_join(
    read_register("lpr_a_kontakt") %>%
      rename_with(tolower) %>%
      select(dw_ek_kontakt, pnr),
    by = "dw_ek_kontakt"
  ) %>%
  mutate(surgery_date = as.Date(proc_starttidspunkt)) %>%
  select(pnr, surgery_date, surgery_code = proc_kode) %>%
  collect()

# Combined
surg_all <- bind_rows(surg_lpr2, surg_lpr3)

6. Other clinical registers

These registers are used less often than those above and are not column-verified here - the descriptions give an overview, but look up the exact variable names in DST’s overview of registers and variable lists and confirm against your own files with colnames().

MFR - Medical Birth Register

One row per birth, carrying both mother and child. The mother appears once per birth, so a mother of three has three rows; the register is keyed on the child through cpr_barn.

Two versions of the same MFR register exist

DST delivers MFR as one wide table, 1997-2018. Sundhedsdatastyrelsen publishes it split across MFR_MOR_* and MFR_BARN_* tables. Check which one your project has before writing code against column names.

gestationsalder_dage is in days, not weeks. paritet counts previous births, which is not the same as the number of children currently alive.

Column Type Role Label Years
alder_moder numeric value ALDER_MODER
bmi_moder numeric value BMI_MODER 2003 to 2018
cpr_barn character join key CPR_BARN
cpr_moder character join key CPR_MODER
flerfoldsfoedsel_beregnet character code FLERFOLDSFOEDSEL_BEREGNET
gestationsalder_dage numeric value GESTATIONSALDER_DAGE
hoejde_moder numeric value HOEJDE_MODER 2003 to 2018
laengde_barn character code LAENGDE_BARN
paritet numeric value PARITET
rygerstatus_moder character code RYGERSTATUS_MODER
vaegt_barn numeric value VAEGT_BARN
vaegt_moder numeric value VAEGT_MODER 2003 to 2018
All other columns (79)
Column Type Role Label Years
abdominalomfang numeric value ABDOMINALOMFANG
abruptio character code ABRUPTIO
afdeling character code AFDELING
alderveddoed_dage_barn numeric value ALDERVEDDOED_DAGE_BARN
alder_fader numeric value ALDER_FADER
amnioinfusion character code AMNIOINFUSION 1998 to 2018
amnitomi_under_foedsel_hsp character code AMNITOMI_UNDER_FOEDSEL_HSP
andensutur character code ANDENSUTUR
apgarscore_efter5minutter numeric value APGARSCORE_EFTER5MINUTTER
barnslevendenr_flerfoldfoedsel numeric value BARNSLEVENDENR_FLERFOLDFOEDSEL
barnsnummer_flerfoldsfoedsel numeric value BARNSNUMMER_FLERFOLDSFOEDSEL
besoeghosjordemoder character code BESOEGHOSJORDEMODER
besoeghoslaege character code BESOEGHOSLAEGE
besoeghosspeciallaege character code BESOEGHOSSPECIALLAEGE
bopaelskommune_moder character code BOPAELSKOMMUNE_MODER
cpapbeh_neonatalafdeling character code CPAPBEH_NEONATALAFDELING 2000 to 2018
cpr_fader character join key CPR_FADER
disproportio character code DISPROPORTIO
doedsdato_barn date date DOEDSDATO_BARN
doedsdato_moder date date DOEDSDATO_MODER
epiduralblokade character code EPIDURALBLOKADE 2000 to 2018
episiotomi character code EPISIOTOMI
fastsiddendemoderkage character code FASTSIDDENDEMODERKAGE
flerfoldsgraviditet character code FLERFOLDSGRAVIDITET
foedested character code FOEDESTED
foedselsaar character code FOEDSELSAAR
foedselsdato date date FOEDSELSDATO
foedselsdiagnose_moder character code FOEDSELSDIAGNOSE_MODER
foedselsloebenummer numeric value
foedselstime character code FOEDSELSTIME
fosterpraesentation character code FOSTERPRAESENTATION
hjemmebesoeg character code HJEMMEBESOEG 2003 to 2018
hovedomfang numeric value HOVEDOMFANG
intrauterin_asfyxi character code INTRAUTERIN_ASFYXI
intrauterin_palpation character code INTRAUTERIN_PALPATION
kejsersnit_modersoenske character code KEJSERSNIT_MODERSOENSKE 2002 to 2018
koen_barn character code KOEN_BARN
levende_eller_doedfoedt character code LEVENDE_ELLER_DOEDFOEDT
markoer_accreta character code MARKOER_ACCRETA
markoer_anaestesi_til_operation character code MARKOER_ANAESTESI_TIL_OPERATION 2000 to 2018
markoer_andre_foedselskomplikati character code
markoer_b_misdannelse character code MARKOER_B_MISDANNELSE
markoer_cardiomyopati character code MARKOER_CARDIOMYOPATI
markoer_graviditetskomplikatio character code MARKOER_GRAVIDITETSKOMPLIKATIO
markoer_haemoperitoneum character code MARKOER_HAEMOPERITONEUM
markoer_hjemmefoedsel_beregnet character code MARKOER_HJEMMEFOEDSEL_BEREGNET
markoer_igangsaettelse character code MARKOER_IGANGSAETTELSE
markoer_infektioner character code MARKOER_INFEKTIONER
markoer_kejsersnit character code MARKOER_KEJSERSNIT
markoer_medicinske_sygdomme character code MARKOER_MEDICINSKE_SYGDOMME
markoer_navlesnorsblod_analyse character code MARKOER_NAVLESNORSBLOD_ANALYSE 2003 to 2018
markoer_perineal_bristning character code MARKOER_PERINEAL_BRISTNING
markoer_post_partum_bloedning character code MARKOER_POST_PARTUM_BLOEDNING
markoer_ruptur character code MARKOER_RUPTUR
markoer_smertelindring character code MARKOER_SMERTELINDRING 1999 to 2018
markoer_ultralyd character code MARKOER_ULTRALYD 1999 to 2018
markoer_vestimulation character code MARKOER_VESTIMULATION 1999 to 2018
markoer_ydre_vending character code MARKOER_YDRE_VENDING
navlesnorsfremfald character code NAVLESNORSFREMFALD
pk_mfr character code PK_MFR
placentavaegt numeric value PLACENTAVAEGT
polyhydramnios character code POLYHYDRAMNIOS
pprom character code PPROM
praevia character code PRAEVIA
prom character code PROM
respiratorbeh_neonatalafdeling character code RESPIRATORBEH_NEONATALAFDELING 2000 to 2018
sengedage_beregnet_barn numeric value SENGEDAGE_BEREGNET_BARN
sengedage_beregnet_moder numeric value SENGEDAGE_BEREGNET_MODER
sengedage_neonatalafdeling_barn numeric value SENGEDAGE_NEONATALAFDELING_BARN
sepsis_barn character code SEPSIS_BARN
skalp_blodproeve character code SKALP_BLODPROEVE 2000 to 2018
suturcollum character code SUTURCOLLUM
sygehus character code SYGEHUS
tang_forloesning character code TANG_FORLOESNING
tegn_paa_asphyxi character code TEGN_PAA_ASPHYXI
tidligerefoedsler_i_danmark character code TIDLIGEREFOEDSLER_I_DANMARK
tidligerekejsersnit_i_danmark character code TIDLIGEREKEJSERSNIT_I_DANMARK
tidligerespontaneaborter character code TIDLIGERESPONTANEABORTER
vakuumekstraktion character code VAKUUMEKSTRAKTION

No published source gives a data type for 91 of these 91 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: cpr_barn.

Joins to other registers:

  • pnr joins to BEF (many-to-one).

Worth knowing:

  • bmi_moder: Only from 2003, unlike most of the register, which starts in 1997.
  • cpr_barn: The child’s CPR number, which is how the register joins to every other register about the child.
  • cpr_moder: The mother’s CPR number. There is a row per child, so a mother of three appears three times.
  • gestationsalder_dage: Gestational age in days, not weeks. Divide by 7 for the usual clinical scale.
  • paritet: Parity. Counts previous births, so it is not the same as the number of children currently alive.

The Cancer Register

The gold standard for incident cancer diagnoses - more complete and precise for cancer than LPR diagnoses. Running since 1943, which makes it one of the longest continuous cancer registries anywhere. Use it for cancer as an outcome or an exclusion.

It is not a DST register. The Cancer Register is held by Sundhedsdatastyrelsen and does not appear in DST’s register list at all: a project reaches it through Forskerservice, on a separate application. The person key is k_cprnr, not pnr, so rename before joining.

One row per tumour, not per person. Somebody with two primary cancers has two rows, distinguished by k_tumornr. Deduplicating on the person alone collapses second primaries and undercounts incidence.

Column Type Role Label Years
c_icd10 character code ICD10 diagnose 1978 to 2024
c_morfo03 character code ICD3 - Histologi og morfologi 1978 to 2024
c_topo3 character code Tumorens lokalisation 1978 to 2024
d_diagnosedato date date Diagnosedato
k_cprnr character join key CPR-nummer
k_tumornr character code Tumor løbenr.
v_diagnosealder numeric value Patientens alder
All other columns (28)
Column Type Role Label Years
c_amtf07 character code Amtskode 1968 to 2006
c_behandling character code Behandlingskode 1943 to 2003
c_diaggr character code Diagnosegruppering ICD7
c_diaggr_kp character code Diagnosegruppering KP 1978 to 2024
c_diaggr_nordcan character code Diagnosegruppering NordCan
c_grad character code Gradering 1943 to 2008
c_idc7 character code ICD7 diagnose 1943 to 1977
c_komf07 character code Patientens bopælskommune 1968 to 2006
c_kommune character code Bopælskommune 1978 to 2024
c_lateral character code Lateralitet
c_makrogrundlag character code Makroskopisk grundlag
c_mikrogrundlag character code Mikroskopisk grundlag
c_orggr character code ICD7 diagnosegruppering
c_orggr_idc10 character code ICD10 diagnosegruppering 1978 to 2024
c_region character code Patientens bopælsregion 2006 to 2024
c_sarc character code Sarcom. eller ej 1943 to 2006
c_sex character code Patientens køn
c_status character code Patientens status
c_tnm_m character code Angiver fjernmetastaser 2004 to 2024
c_tnm_n character code Angiver lymfeknudemetastaser 2004 to 2024
c_tmn_t character code Størrelse af tumor 2004 to 2024
c_udbred character code Tumorens udbredelse 1943 to 2003
c_udbred_klassifikation character code Anvendt udbredelsesklassifikation
c_aa character code Ann Arbour klassifikation 2004 to 2024
d_fdsdato date date Fødselsdato
d_statdato date date Status dato
v_diagmd numeric value Diagnosemåned
v_diagaar numeric value Diagnoseår
  • c_grad: Only filled in for urinary tract tumours.
  • c_idc7: ICD-7, the coding used before ICD-10. A series running back before 1978 needs both this and c_icd10.
  • c_udbred: Replaced by the TNM columns and Ann Arbor from 2004, when the register moved from paper coding to electronic reporting through LPR. Nothing maps one to the other, so a stage variable across 2004 is two different things.

Join key: k_cprnr.

Joins to other registers:

  • k_cprnr joins to BEF (many-to-one).
Value sets for the coded columns (3)
Code system Values
icd10 Not listed here - see DST’s classification
kom Not listed here - see DST’s classification
reg 0 Uoplyst, 81 Nordjylland, 82 Midtjylland, 83 Syddanmark, 84 Hovedstaden, 85 Sjælland
  • icd10: Do not strip a leading D from these codes. The habit comes from LPR, where the D is really there, and applying it here removes the first character of a real code: E119 becomes 119, which matches nothing and raises no error. The danger is worst where a code genuinely begins with D. ICD-10 chapter D covers in-situ and benign neoplasms, so D46 is myelodysplastic syndrome, a whole code. Strip its “prefix” and you get 46, which looks like a code and is not one.
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.
  • reg: Do not confuse these with AMT, the pre-2007 counties, which has 16 codes in the ranges 11-14, 21-24, 31-37 and 88. Different geography, different era.

Where these values come from:

Worth knowing:

  • c_icd10: The modern diagnosis code. Older years also carry ICD-7 in c_idc7, so a series running back before ICD-10 has to use both.
  • c_morfo03: Histology and morphology, ICD-O-3. Together with c_topo3 (site) this is what distinguishes tumour types; the ICD-10 code alone does not.
  • d_diagnosedato: The diagnosis date, which is the incidence date for this register.
  • k_cprnr: The person key. Named k_cprnr rather than pnr, so rename before joining to a DST register.
  • k_tumornr: One person can appear several times: the register counts incident tumours, not people. Deduplicating on the person alone collapses second primaries.
  • v_diagnosealder: Age at diagnosis, precomputed. Recompute from d_fdsdato if your index date differs.

Primary sector - sysi and sssy (Health Insurance Register)

Contacts and services in the primary sector (general practice, practising specialists, physiotherapy etc.). As with LPR, the register is split over time: sysi covers the older years, sssy the newer. Join via pnr. Use it for e.g. GP/specialist contacts, screening or vaccinations billed in primary care. Key fields are named the same in both, but the two registers do not carry an identical column set, so verify with colnames(). They overlap in 2005: both report that year, so reading both without picking a source double-counts it.

sysi (1990-2005):

Column Type Role Label
pnr character join key Personal identifier
ydernr character identifier Provider number
speciale character code Specialty, 6-digit
ydlant integer value Number of services under the specialty
afrper character date Settlement period
sikgrup character code Insurance group
year integer date Register year
All other columns (15)
Column Type Role Label Years
ydtyp character code Provider type
ydltid character code Service timing code
ydersamt character code Provider’s county
bruhon numeric value Gross fee to the provider
honuge character date Fee week
barnmak character code Child marker
pattyp character code Patient type
praktyp character code Practice type
sikrekom character code Municipality of the insured
grdhon character code GRUNDHONORAR 1997 to 2005
henvisni character code Henvisningsydernummer
paragraf character code PARAGRAFRELATION 1997 to 2005
praksiso character code PRAKSISOMRÅDE 1997 to 2005
sikreamt character code Sikredes amt
vagtomr character code VAGTOMRÅDE 1997 to 2005

No published source gives a data type for 21 of these 22 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (1)
Code system Values
kom Not listed here - see DST’s classification
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.

Where these values come from:

Worth knowing:

  • ydernr: A provider number, not a person. DST’s variable list does not say what unit it identifies or whether it is stable when a practice changes hands, so do not use it to follow an individual clinician over time without checking that first.
  • speciale: The 6-digit specialty code is what distinguishes a GP contact from a specialist one. There is no separate contact-type column: the specialty is the classification.
  • ydlant: One row can cover several services, so counting rows undercounts activity. Sum this column instead.
  • afrper: DST labels this “Afregningsperiode”, a settlement period rather than a treatment date. Nothing in the variable list says how far settlement can lag the contact, so check the distribution against honuge before using it as a date.
  • sikgrup: Group 1 patients need a referral from their GP to see a specialist, physiotherapist, chiropodist or psychologist, and pay nothing. Group 2 patients may go directly to any GP or specialist, but pay the difference between the fee and the regional subsidy themselves. The two groups therefore leave different traces for the same clinical need, so group membership is a confounder in any analysis of specialist use. Source: borger.dk, “Sygesikring og sikringsgrupper”.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

sssy (2005-2025):

Column Type Role Label
pnr character join key Personal identifier
ydernr character identifier Provider number
speciale character code Specialty, 6-digit
ydlant numeric value Number of services under the specialty
afrper character date Settlement period
sikgrup character code Insurance group
year integer date Register year
All other columns (18)
Column Type Role Label Years
ydtyp character code Provider type
ydltid character code Service timing code
ydersamt character code Provider’s county
bruhon numeric value Gross fee to the provider
honuge character date Fee week
barnmak character code Child marker
kontakt numeric value Contact
patgrp character code Patient group
koenimp character code Sex, imputed values included
alderimp numeric value Alder ultimo inkl. imputerede
behandlingsdato date date 2021 to 2025
cprtjek character code CPR-tjek
cprtype character code CPR-type
registreringstid character code 2021 to 2025
spec2 character code 2-cifret speciale
spec80 character code 2021 to 2025
statpop character code 2021 to 2025
version numeric date Version pr. referencetidspunkt for Moduldata
  • kontakt: Not in SYSI. Do not assume a comparable count of contacts before 2005.
  • koenimp: Imputed where the source was missing, so it is not identical to koen in BEF. Prefer BEF when you need sex as a study variable.

No published source gives a data type for 6 of these 25 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (1)
Code system Values
koen 1 Mand, 2 Kvinde, 9 Uoplyst
  • koen: DST’s classification KOEN_V1_1980 also defines 9 for not stated, which a delivery may not contain but a value set should. Sex is taken from the tenth digit of the CPR number: even is female, odd is male.

Where these values come from:

Worth knowing:

  • ydernr: A provider number, not a person. DST’s variable list does not say what unit it identifies or whether it is stable when a practice changes hands, so do not use it to follow an individual clinician over time without checking that first.
  • speciale: The 6-digit specialty code is what distinguishes a GP contact from a specialist one. There is no separate contact-type column: the specialty is the classification.
  • ydlant: One row can cover several services, so counting rows undercounts activity. Sum this column instead.
  • afrper: DST labels this “Afregningsperiode”, a settlement period rather than a treatment date. Nothing in the variable list says how far settlement can lag the contact, so check the distribution against honuge before using it as a date.
  • sikgrup: Group 1 patients need a referral from their GP to see a specialist, physiotherapist, chiropodist or psychologist, and pay nothing. Group 2 patients may go directly to any GP or specialist, but pay the difference between the fee and the regional subsidy themselves. The two groups therefore leave different traces for the same clinical need, so group membership is a confounder in any analysis of specialist use. Source: borger.dk, “Sygesikring og sikringsgrupper”.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.

Laboratory results - Laboratoriedatabasens Forskertabel

Laboratory and blood test results: HbA1c, lipids, creatinine. A very large register, well over a billion rows, so filter with arrow or duckplyr before you collect() into R.

It is not a DST register. This is Laboratoriedatabasens Forskertabel (LAB_F), held by Sundhedsdatastyrelsen and reached through Forskerservice. It is not in DST’s register list, the table names are project-specific, and the columns are named in English: patient_cpr, analysiscode, samplingdate, value, unit. NPU is the coding system used in analysiscode, not a column name.

value is text, not a number. Alongside numeric results it holds a fixed set of words - POSITIV, NEGATIV, IKKE PÅVIST, INGEN VÆKST and the blood type codes. as.numeric() turns every one of them into NA without warning, which drops exactly the samples where something was found.

Coverage starts in 2008, not the 1990s, and complete coverage arrives per laboratory between 2010 and 2016. Only NPU- and DNK-coded results reach the table, about 95 per cent; results with a laboratory’s own local code are absent, as are patients who declined consent. See Laboratoriedatabasen →.

DARTER: a dedicated extraction guide for laboratorieproevesvar_ is in progress - see DARTER - Register paths and datastores.

Healthcare costs (under development)

Under development - confirm everything in your own delivery. This section describes cost sources at the register level. Exact table and column names and the available years change from year to year (the DRG rate system is updated annually) and are not verified here. Use it as a pointer, and clarify the specific files with your data manager.

To compute healthcare use/costs per person, they are typically assembled from several sources:

  • Somatic hospital contacts: DRG-grouped rates from the Danish Health Data Authority (DRG = inpatient, DAG = outpatient). Rates express average operating expenses per DRG group and are computed annually - see SDS DRG rates.
  • Psychiatric hospital contacts: are not billed by DRG. The main principle is a bed-day rate for inpatients and a visit rate for outpatients - keep somatic and psychiatric separate.
  • Primary sector (general practice, specialists etc.): fees in sysi/sssy (see the section above).
  • Medication: patient co-payment vs. reimbursement in LMDB (section 7).

Availability of cost data varies (some years/sources are missing, e.g. more recent DRG years). The pattern is inspired by the Plana-Ripoll group’s code on OSF, but the variable names there are from a 2022 delivery and should not be assumed current.

7. LMDB - Prescription Register

Owned by the Danish Health Data Authority as the Prescription Register: Lægemiddelstatistikregisteret →.

One row per dispensed prescription. Covers approximately 1994 onwards.

Column Type Role Label Years
pnr character join key Personal identifier 1995-Q2 to 2025-Q2
eksd date date Dispensing date 1995-Q2 to 2025-Q2
atc character code ATC code, full 7 characters 1995-Q2 to 2025-Q2
atc1 character code ATC level 1 (1 character) 1995-Q2 to 2025-Q2
atc2 character code ATC level 2 (3 characters) 1995-Q2 to 2025-Q2
atc3 character code ATC level 3 (4 characters) 1995-Q2 to 2025-Q2
atc4 character code ATC level 4 (5 characters) 1995-Q2 to 2025-Q2
vnr character code Item number (product key) 1995-Q2 to 2025-Q2
apk numeric value Number of packages 1995-Q2 to 2025-Q2
year integer date Dispensing year
All other columns (55)
Column Type Role Label Years
indo character code Indication code 2004-Q2 to 2025-Q2
packsize numeric value Package size 1995-Q2 to 2025-Q2
strnum numeric value Strength, numeric 1995-Q2 to 2025-Q2
strunit character value Unit for the numeric strength 1995-Q2 to 2025-Q2
aldr numeric value Age at dispensing 1995 to 2025
abc character code ABC-kode 2007 to 2025
aip numeric value Registerpris (‘Apotekets indkøbspris’) (s) 1995 to 2025
aref character code Andre refusionsordninger 1995 to 2025
aup numeric value Registerpris (‘Apotekets udsalgspris’) (s) 1995 to 2025
bald character code 1995 to 2011
cprtjek character code CPR-tjek 1995 to 2025
cprtype character code CPR-type 1995 to 2025
cpr_kom character code CPR-bopælskommune på ekspeditionsdatoen 2005 to 2025
cpr_reg character code CPR-bopælsregion på ekspeditionsdatoen 2005 to 2025
dosform character code Lægemiddelform (s) 1995 to 2025
doso character code Doseringskode 2004 to 2025
edbl character code 2020 to 2025
ejs character code Fravalg af substitution 1997 to 2025
eksp numeric value Ekspeditionspris 1995 to 2025
ekst character code Ekspeditionstype 1995 to 2025
etid numeric date Ekspeditionstidspunkt 1997 to 2025
ibgp numeric value Indberettet beregningsgrundlagspris 2000 to 2025
ibnr character code Indberetternummer 1995 to 2025
itype character code Indberettertype 1995 to 2025
kom character code Kommunekode 1995 to 2025
korr character code Korrektionskode 1995 to 2025
name character code Lægemidlets navn (Store bogstaver) (s) 1995 to 2025
ovnr character code Ordineret varenummer 1997 to 2025
packtext character code PACKTEXT 1995 to 2025
patt character code Patienttype 2000 to 2025
pksubgr character code Pakningssubstitutionsgruppe 2007 to 2025
pnr12 character join key CPR-nummer 1995 to 2025
pprs character code Udleveringsbestemmelse 1995 to 2025
ptp character code Patientbetaling 1995 to 2025
ramt character code Amtskommunekode 1995 to 2025
reca character code Autorisationskode for receptudsteder 2005 to 2025
recu character code Receptudsteder 1995 to 2025
rgl1 character code 1. Kommuneregelnummer 1995 to 2025
rgl2 character code 2. kommuneregelnummer 1995 to 2025
rgla character code Amtskommunalt reglnummer 1995 to 2025
rimb character code Tilskudskode 1995 to 2025
rinr character code Reiterationsnummer 1995 to 2025
sektor character code Sektor 1995 to 2025
streng character code Styrke, klartekst (s) 1995 to 2025
takd date date Takstdato 1995 to 2025
tard date date Takseringsdato 2000 to 2025
tilpris numeric value Tilskudspris pr. pakning 1995 to 2025
tsk1 character code 1. Kommunale tilskud 1995 to 2025
tsk2 character code 2. Kommunale tilskud 1995 to 2025
tsk3 character code Andre tilskud 1995 to 2025
tska character code Amtskommunalt tilskud 1995 to 2025
udlv character code Udleveringssted 1995 to 2025
voltypecode character code 1995 to 2025
voltypetxt character code 1995 to 2025
volume character code Volume 1995 to 2025
  • indo: Recorded only when the prescriber picks an indication from the drop-down. Typed as free text it is not carried over, so the column is often empty.

No published source gives a data type for 28 of these 65 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (3)
Code system Values
atc Not listed here - see DST’s classification
kom Not listed here - see DST’s classification
reg 0 Uoplyst, 81 Nordjylland, 82 Midtjylland, 83 Syddanmark, 84 Hovedstaden, 85 Sjælland
  • atc: As a rule, filter on the full 7-character code rather than on the level columns: atc2 holds three characters, so a longer pattern matched against it can never match, and it returns nothing at all with no error. The level columns are well suited to grouping, and to filtering when every code you want is the same length as the column.
  • kom: These codes are valid from 1 January 2007. A study reaching further back needs the pre-reform classification, where the same number can mean a different municipality - confirmed for two reused codes against a current-only DST source: 707 is Norddjurs today, not its pre-2007 meaning, and likewise 849 is Jammerbugt. lookup: below covers only this post-2007 set (99 entries), not the full 278-code values_from file. Christiansø (411) is included in lookup: even though it is not a municipality (see description above): it is a real value a kom column can hold, and DST’s own current-only classification lists it as its own area code alongside the 98 municipalities. Excluding it would just move the “unhandled code” problem this fix is meant to solve onto that one value.
  • reg: Do not confuse these with AMT, the pre-2007 counties, which has 16 codes in the ranges 11-14, 21-24, 31-37 and 88. Different geography, different era.

Where these values come from:

Worth knowing:

  • pnr: DST’s variable list calls this column PNR12. Check whether your variable is named pnr or pnr12. Do not confuse this with the pnr documented on esundhed’s page for this register (DocumentationExtended?id=14): that pnr is the pharmacy or manufacturer’s production-unit number, length 10, not a person. Same name, unrelated variable, on the two pages that between them cover this register.
  • eksd: The date the prescription was collected at the pharmacy. Not the date it was prescribed, and not evidence that the medicine was taken.
  • vnr: The only reliable way to isolate one specific product. Two brands with the same active substance share an ATC code but have different item numbers.
  • year: Not a DST variable. It comes from fastreg’s parquet conversion, which concatenates the yearly deliveries, so it exists in the data you read but not in DST’s own documentation of this register.
All confirmed columns in LMDB

pnr, eksd, ekst, atc, atc1, atc2, atc3, atc4, indo, vnr, apk, aldr, bald, eksp, korr, rinr, name, streng, packtext, volume, voltypecode, voltypetxt, dosform, strnum, strunit, packsize, cprtjek, cprtype, year, etid, ovnr, patt, doso, reca, abc

Filtering on atc2 fails silently. The level columns are shorter than the full code: atc2 holds three characters, so grepl("N02A", atc2) matches nothing and returns zero rows without an error. Filter on atc and keep the level columns for grouping. Details, and a check you can run on your own extract, are in Medication (ATC).

Data quality of indo and doso

indo (indication code) is recorded only when the doctor picks an indication from the drop-down menu in the electronic prescription; typed as free text, it is not carried over. It is therefore missing on about 12-18% of prescriptions (more before 1 October 2017) and is often nonspecific. The dosage field doso is effectively empty (recorded for ~0.06% of prescriptions). See Medication (ATC) for how to handle this.

8. Socioeconomic registers

All three registers are used for SEP extraction following SEPLINE guidelines (Hjorth et al. 2025). No single combined SEP variable is calculated - three separate dimensions.

UDDA - Education Register

One record per person per year - updated when the education level changes.

Column Type Role Label Years
pnr character join key Personal identifier 1980 to 2025
hfaudd character code Highest completed education 1980 to 2025
udd character code Education code 1980 to 2025
hf_vfra date date Date the education was completed 1980 to 2025
year integer date Register year
All other columns (13)
Column Type Role Label Years
hf_kilde character code Source of the education record 1980 to 2025
hfinstnr character code Institution that awarded the education 1980 to 2025
almaudd character code Highest completed general education 1980 to 2025
erhaudd character code Highest completed vocational education 1980 to 2025
alm_vfra date date Date the general education was obtained 1980 to 2025
erh_vfra date date Date the vocational education was obtained 1980 to 2025
ig_vfra date date Start date of the ongoing education 1980 to 2025
alminstnr character code Institution, general education 1980 to 2025
erhinstnr character code Institution, vocational education 1980 to 2025
iginstnr character code Institution, ongoing education 1980 to 2025
cprtjek character code CPR check 2005 to 2025
cprtype character code CPR type 2005 to 2025
version character code Module data version 2005 to 2025
  • hfinstnr: The guide previously referred to this column as INSTNR. DST’s list has no INSTNR; the institution columns are HFINSTNR, ALMINSTNR, ERHINSTNR and IGINSTNR, one per kind of education.
  • almaudd: The general-education track only. hfaudd is the highest completed education of any kind, so the two answer different questions and are not interchangeable.
  • ig_vfra: Pairs with udd: this is when the ongoing education began. An education with a start and no completion is either still running or was interrupted, and the register does not distinguish the two.

No published source gives a data type for 17 of these 18 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (1)
Code system Values
hfaudd Not listed here - see DST’s classification
  • hfaudd: This is an identifier, not a scale. The level (short, medium, long) has to be looked up in a separate table, and cannot be read off the digits: 4112 is an electrician, and taking the first two digits as a level code makes it a long higher education. DST documents the ongoing-education codes separately as DISCED-15 UDD.

Where these values come from:

Worth knowing:

  • hfaudd: A code for which education, not for its level. UDDA carries no level column at all, so the level has to come from a lookup table.
  • udd: Not the same code system as hfaudd. Under DISCED-15, AUDD codes describe a completed education and UDD codes one that is ongoing or was interrupted, so a lookup table built for one will not fit the other.
  • year: Not a DST variable. It is the partition the yearly deliveries were written into, so filtering on it stops the other years being read at all. Use it to limit how much is read, not to decide when something happened: for that, use the register’s own date column.
Importanthfaudd is not an education level - do not read the digits

This is the single easiest mistake to make with UDDA, and it produces wrong numbers without any error message. There are two different code systems, and they look confusingly alike:

What it identifies Example
Education code (hfaudd) Which education, as a four-digit DISCED-15 code 4112 = electrician
Level code How long/high the education is, two digits 30 = vocational, 70 = master’s

hfaudd is an identifier, not a scale. The first two digits are simply the start of a serial number, and there is no arithmetic relationship between the two systems. Taking substr(hfaudd, 1, 2) and treating it as the level is wrong, and it fails in both directions:

  • hfaudd = 4112 is an electrician - vocational, level 30. Reading 41 and comparing it to 40 makes it a long higher education.
  • hfaudd = 141 is genuinely level 40, short cycle higher education. Reading 14 matches no level at all, so a real education becomes missing data.

UDDA does not contain the level. DST’s education register holds only HFAUDD, HF_KILDE, HF_VFRA, HF_VTIL and INSTNR - there is no level column to read. The level has to come from a lookup table that maps each education code to its level. See Socioeconomic variables for how to do it.

How often the substr() shortcut is actually wrong

Tested against the full DISCED-15 list, the rule gets 58% of the 4,621 codes right, and 1,149 of them land in a confidently wrong category rather than in “unknown”. So it is not a rule that fails loudly on odd cases: it is right often enough to look like it works, and wrong often enough to move real numbers.

It looks plausible because the level codes (10, 15, 20, 30, 40, 70, 90) have the same shape as the first two digits of an education code. That resemblance is a coincidence of how the serial numbers were assigned, not a mapping.

AUDD or UDD - pick the right lookup. DISCED-15 has one code for an education that is ongoing or interrupted (UDD) and one for a completed education (AUDD), and DST publishes format tables for both. hfaudd is højest fuldførte AUDD, the highest completed education, so an audd lookup is the one that fits. A udd table will still join - it will just match some rows, miss others, and never tell you. Naming and paths are in Format tables.

FAIK - Family Income

Household-equivalised disposable income per year. Link: join BEF (pnr, familie_id, year) with FAIK (familie_id, year).

The structure can differ between years. On DARTER, FAIK from 2022 onward also carries pnr, and the family’s row is repeated once per family member instead of appearing once. Joining on familie_id alone then multiplies your rows silently. Check your own delivery before you rely on the join - how, and what to do about it, is in Socioeconomic variables.

Column Type Role Label Years
pnr character join key Personal identifier
familie_id character join key Household key
famaekvivadisp_13 numeric value Household-equivalised disposable income
year integer date Register year
famdisponibel_13 numeric value Disposable income
famindkomstialt_13 numeric value Total income before taxes
famsociogrup_13 numeric code Socioeconomic group, 2013 definition 1993 to 2024
famtype numeric code Family type
All other columns (79)
Column Type Role Label Years
famaekvivadisp numeric value Equivalised disposable family income 1990 to 2012
famaekvivaindknetto numeric value Equivalised total income including net interest 1990 to 2012
famaktieindk numeric value Share income 1990 to 2009
famandenpension numeric value Other pension payments to the family
famandoverforsel numeric value Other transfers to the family 1990 to 2012
famantalfskattepligtige numeric value Number of fully taxable adults in the family
famarbejdsloesp numeric value Unemployment benefit and training allowance
famarbmabidrag numeric value Labour market contributions
famboernetilskud numeric value Child benefit and family allowances
famboligform numeric code Housing tenure 2000 to 2024
famboligstoette numeric value Housing benefit paid to the family
famboligtype numeric code Dwelling type 2000 to 2024
fambruttoindk numeric value Gross family income 1990 to 2009
famdagpenge_kontant_13 numeric value Total benefits and social assistance
famdisponibel numeric value Disposable family income 1990 to 2012
famefterloen numeric value Early retirement pay
famejdskat_ejerbolig numeric value Property tax, homeowners 2010 to 2024
famejdskat_lejerbolig numeric value Property tax, tenants 2010 to 2024
famejendomsvurdering numeric value Cash property value
famerhvervsindk numeric value Business income for the family 1990 to 2012
famerhvervsindk_13 numeric value Business income: wages and net profit
famfolkefortid_13 numeric value State and early retirement pension in the family
famformrest_ny05 numeric value Net residual wealth at year end
famformueaktiver numeric value Total assets
famformueindk numeric value Total capital income for the family 1990 to 2012
famformueindk_brutto numeric value Capital income, gross
famfradragialt numeric value Total calculated deductions 1990 to 2012
famfrynsegoder numeric value Taxable value of fringe benefits 1993 to 2009
famgaeldialt numeric value Liabilities
famgron_check numeric value Green check 2010 to 2024
famhoejstudda character code Highest education among the adults 2000 to 2024
famhonny numeric value Fees liable to labour market contributions
famindkomstialt numeric value Total family income before tax 1990 to 2012
famkontanthjaelp numeric value Social assistance for the family 1990 to 2009
famkontanthjaelp_13 numeric value Social assistance in the family
famlejevaerdi numeric value Imputed rental value of owner-occupied dwelling 1990 to 2012
famlejev_egen_bolig numeric value Imputed rental value of owner-occupied dwelling
famloenmv numeric value Total wage income in the family 1990 to 2012
famloenmv_13 numeric value Total wage income in the family
fammidlertidyd numeric value Temporary transfer incomes 1990 to 2012
famoevrigformue numeric value Other capital income for the family 1990 to 2009
famoevrigformue_13 numeric value Other capital incomes in the family
famoffpens_eftlon_13 numeric value Public pensions in the family
famoff_overforsel_13 numeric value Public transfers to the family
famorlovsydelse numeric value Leave benefits paid to the family 1994 to 2009
famoverfoerindk numeric value Total transfer incomes 1990 to 2012
famovergangyd numeric value Total transitional allowance 1994 to 2006
famovrig_dagpenge_akas_13 numeric value Other benefits from unemployment funds
famovrig_kontanthjalp_13 numeric value Activation, unemployment and rehabilitation allowance
famovrig_overforsel_13 numeric value Other transfer incomes in the family
fampensionatp numeric value ATP pension payments
fampensionialt numeric value Total pensions for the family 1990 to 2012
fampensoffentlig numeric value State and early retirement pension 1990 to 2009
fampenstjeneste numeric value Civil servant pension
famprivat_pension_13 numeric value Private pensions in the family
famrenteindk numeric value Total interest income from Denmark 1990 to 2009
famrenteindk_13 numeric value Total taxable interest income
famrenteudgifter numeric value Total deductible interest expenses 1990 to 2012
famrenteudgifter_13 numeric value Interest expenses
famrestbistandsyd numeric value Other benefits from municipalities and unemployment funds 1990 to 2009
famrestindk numeric value Miscellaneous unclassified income 1990 to 2012
famrestindk_13 numeric value Other personal income in the family
famsamletindk numeric value Total income for the family 1990 to 2009
famskatfriyd numeric value Tax-free incomes in the family 1990 to 2012
famskatmvialt numeric value Tax and labour market contributions paid 1990 to 2012
famskatmvialt_13 numeric value Tax, labour market contributions and special pension
famskatpligtindk numeric value Taxable income for the family
famskattot numeric value Total income tax paid 1990 to 2009
famskattot_13 numeric value Total personal final tax
famsociogrup numeric code Socioeconomic group 1994 to 2009
famsu numeric value State education grants (SU)
famsumindknettorent numeric value Total income including net interest 1990 to 2012
famsyg_barsel_13 numeric value Sickness and maternity benefits
famtransportfradrag numeric value Total commuting deduction 1990 to 2009
famunderhbidrag numeric value Maintenance payments made by the family
famvirkordind numeric value Amounts placed in the business tax schemes
famvirkoverskud numeric value Net profit from self-employment 1990 to 2009
famvirkoverskud_13 numeric value Total profit from self-employment
version numeric code Module data version
  • famaekvivadisp: The same weighting scheme as FAMAEKVIVADISP_13 below, just algebraically rearranged on the source page: the first adult over 14 counts as 1.0, each further person over 14 as 0.5, and each child under 15 as 0.3. All persons belonging to the same family on 31 December of the income year (same E-familienummer), including resident children under 25, are assigned the family’s equivalised income. FAMDISPONIBEL is the same money before that division.

No published source gives a data type for 67 of these 87 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: familie_id.

Joins to other registers:

  • familie_id joins to BEF (one-to-many).
Value sets for the coded columns (3)
Code system Values
famboligform 1 Ejerbolig, 2 Lejebolig, 9 Uoplyst
socio13 11 Selvstændige, 110 Selvstændige, 111 Selvstændige erhvervsdrivende med 10 eller flere ansatte, 112 Selvstændige erhvervsdrivende med 5-9 ansatte, 113 Selvstændige erhvervsdrivende med 1-4 ansatte, 114 Selvstændige erhvervsdrivende uden ansatte, 12 Medarbejdende ægtefælle, 120 Medarbejdende ægtefælle, 13 Lønmodtagere, 131 Lønmodtagere med ledelsesarbejde, 132 Lønmodtager i arbejde der forudsætter færdigheder på højeste niveau, 133 Lønmodtager i arbejde der forudsætter færdigheder på mellemniveau, 134 Lønmodtager i arbejde der forudsætter færdigheder på grundniveau, 135 Andre lønmodtagere, 139 Lønmodtager uden nærmere angivelse, 21 Arbejdsløs mindst halvdelen af året, 210 Arbejdsløse mindst halvdelen af året, 22 Sygedagpenge, orlov mv., 220 Modtager af sygedagpenge, uddannelsesgodtgørelse, orlovsydelser mv., 31 Uddannelsessøgende, 310 Under uddannelse, inkl. skoleelever på min. 15 år, 32 Pensionist/efterløn, 321 Førtidspensionister, 322 Folkepensionister, 323 Efterlønsmodtagere mv., 33 Kontanthjælp, 330 Kontanthjælpsmodtagere, 41 Andre, 410 Andre, 42 Børn, 420 Børn under 15 år, ultimo året
famtype 0 Ingen oplysninger, 1 Ægtepar forskelligt køn, 2 Registreret partnerskab, 3 Samlevende par, 4 Samboende par, 6 Enlig mænd (herunder også ikke hjemmeboende børn), 7 Enlig kvinder (herunder også ikke hjemmeboende børn), 8 Ægtepar samme køn
  • socio13: Two codes are easy to misread. 410 is Andre (other), not unemployed: the unemployed are 210. And 420 is children under 15, a known category rather than a missing value, so it appearing in an adult cohort means the index date is wrong rather than the data being incomplete.
  • famtype: There is no code 5. The sequence runs 0 to 4 and then 6 to 8, which is easy to read as a missing value rather than as a code that never existed.

Where these values come from:

How it is computed:

famaekvivadisp_13

FAMAEKVIVADISP_13 = FAMDISPONIBEL_13 / (1 + (0.5 * (number of people over 14 in the family - 1)) + (0.3 * number of people under 15 in the family))

famaekvivadisp

FAMAEKVIVADISP = FAMDISPONIBEL / (0.5 + (0.5 * number of people over 14 in the family) + (0.3 * number of people under 15 in the family))

famaekvivaindknetto

FAMAEKVIVAINDKNETTO = FAMSUMINDKNETTORENT / (0.5 + (0.5 * number of people over 14 in the family) + (0.3 * number of people under 15 in the family))
  • FAMANDOVERFORSEL = FAMOEVRIG_OVERFORSEL_13 + FAMGRON_CHECK (from 2010) famdagpenge_kontant_13
FAMDAGPENGE_KONTANT_13 = FAMARBLHUMV + FAMOVRIG_DAGPENGE_AKAS_13 + FAMKONTANTHJ_13 + FAMOVRIG_KONTANTHJALP_13 + FAMSYG_BARSEL_13
  • FAMDISPONIBEL = FAMSUMINDKNETTORENT - FAMSKATMVIALT - FAMUNDERHBIDRAG famdisponibel_13
FAMDISPONIBEL_13 = FAMINDKOMSTIALT_13 + FAMLEJEV_EGEN_BOLIG - FAMRENTEUDGIFTER_13 - FAMSKATMVIALT_13 - FAMUNDERHBIDRAG
  • FAMERHVERVSINDK = FAMLOENMV + FAMVIRKOVERSKUD
  • FAMFORMUEINDK = FAMRENTEINDK + FAMOEVRIGFORMUE + FAMLEJEVAERDI famfradragialt
FAMFRADRAGIALT = FAMBRUTTOINDK - FAMSKATPLIGTIGINDK - FAMARBMABIDRAG (from 1994)

famindkomstialt_13

FAMINDKOMSTIALT_13 = FAMERHVERVSINDK_13 + FAMOFF_OVERFORSEL_13 + FAMPRIVAT_PENSION_13 + FAMRENTEINDK_13 + FAMOEVRIGFORMUE_13 + FAMRESTINDK_13

fammidlertidyd

FAMMIDLERTIDYD = FAMKONTANTHJAELP + FAMARBEJDSLOESP + FAMORLOVSYDELSE + FAMRESTBISTANDYD

fampensionialt

FAMPENSIONIALT = FAMPENSOFFENTLIG + FAMPENSIONATP + FAMEFTERLOEN + FAMOVERGANGYD (1994-2006) + FAMPENSTJENESTE (from 1991) + FAMANDENPENSION

famrestindk

FAMRESTINDK = FAMINDKOMSTIALT - FAMERHVERVSINDK - FAMOVERFOERINDK - FAMFORMUEINDK
  • FAMSKATMVIALT = FAMSKATTOT + FAMARBMABIDRAG famsumindknettorent
FAMSUMINDKNETTORENT = FAMINDKOMSTIALT + FAMLEJEVAERDI - FAMRENTEUDGIFTER

Worth knowing:

  • pnr: Not in DST’s variable list for FAIK, which documents the register as keyed on the household. Where it is present, the household’s row is repeated once per family member, so joining on familie_id alone multiplies rows.
  • familie_id: There is no person identifier here. Fetch familie_id from BEF for the relevant year, then join on it.
  • famaekvivadisp_13: This is the family’s disposable income divided by an equivalence factor, so that families of different sizes can be compared. The factor counts the first adult as 1.0, each further person over 14 as 0.5, and each child under 15 as 0.3: a couple with two young children comes to 1 + 0.5 + 0.6 = 2.1, so a family income of 420,000 is recorded as 200,000 for each of the four. FAMDISPONIBEL_13 is the same money before that division, and FAMAEKVIVAINDKNETTO is a different income concept (total income with net interest), so check which one your analysis plan means. The _13 suffix marks the definition that replaced the older variables from 2013: DST states that FAMDISPONIBEL was discontinued in 2013 and replaced by FAMDISPONIBEL_13. A study spanning 2013 has to know which side of that change it is on. DST’s year ranges settle the relationship with the sister column FAMAEKVIVADISP, which has no _13: the old one runs 1990-2012, this one runs 1987-2024. The _13 definition was applied backwards as well as forwards, so it is not a newer variable covering later years only. A study spanning the 2013 changeover should use _13 for the whole period rather than splicing the two, which would mix two definitions in one series.
  • year: Not a DST variable. It comes from fastreg’s parquet conversion, which concatenates the yearly deliveries, so it exists in the data you read but not in DST’s own documentation of this register.

Income quintiles are calculated as 3-year averages compared against Q20/Q40/Q60/Q80 cut-points from the full BEF population stratified by sex × 5-year age group × reference year.

AKM - Labour Classification Module

Labour market status per person per year.

Column Type Role Label Years
pnr character join key Personal identifier
socio13 integer code Socioeconomic classification, 2013 version 1991 to 2024
socio02 integer code Socioeconomic classification, 2002 version 2002 to 2013
socio integer code Socioeconomic classification, 1994-2001 version 1994 to 2001
socio_gl integer code Socioeconomic classification, 1976-1990 version 1976 to 1990
year integer date Register year
All other columns (41)
Column Type Role Label Years
beskst13 integer code Main source of income 1991 to 2024
disco08_alle_indk_13 character code Occupation code, DISCO-08 2010 to 2024
nace_db07_13 character code Industry, DB07 2007 to 2024
alder_ult_ink integer value Age at 31 December 1991 to 2024
ant_ansat_arbsted numeric value Antal ansatte for væsentligste arbejdssted ( optælling af ansatte sker for hver arbejdessted under SENR (AKM) 2006 to 2013
ant_ansat_arbsted_13 numeric value Antal ansatte for væsentligste arbejdssted ( optælling af ansatte sker for hver arbejdessted under SENR (AKM) 2010 to 2024
ant_ansat_senr numeric value Antal ansatte for væsentligste beskæftigelse (AKM) 1976 to 2005
atpsum2 numeric value Beskæftigelsesmål baseret på ATP- indbetalinger (AKM) 1976 to 2010
beskst numeric code Beskæftigelsesstatus 1980 til 2001 (Indkomst/AKM) 1976 to 2001
beskst02 numeric code Beskæftigelsesstatus fra 2002 (Indkomst/AKM) 2002 to 2013
branche_77 character code Dansk branchekode 1977 til 1993 (AKM) 1980 to 1999
brchi character code Branchekode for indehaver 1976 to 2002
brchl character code Branchekode for lønmodtager 1976 to 1999
cprtjek character code CPR-tjek 1991 to 2024
cprtype character code CPR-type 1991 to 2024
disco08_alle_indk character code Fagklassifikation for beskæftigelsesforhold, fra 2010 (AKM) 2010 to 2013
disco08_loen_indk character code Fagkode for væsentligste lønmodtagerbeskæftigelse i året. (AKM) 2010 to 2024
disco08_sel_indk character code Fagkode for arbejde i selvstændig virksomhed (AKM) 2010 to 2024
discoalle_indk character code Fagklassifikation for beskæftigelsesforhold, fra 1991 TIL 2009 (AKM) 1993 to 2009
discoloen_indk character code Fagkode for væsentligste lønmodtagerbeskæftigelse i året. (AKM) 1991 to 2009
discosel_indk character code Fagkode for arbejde i selvstændig virksomhed (AKM) 1991 to 2009
discotyp character code Kilde til lønmodtager DISCO-koden (AKM) 1991 to 2024
disco_alle_indk_13 character code Fagklassifikation for beskæftigelsesforhold, fra 1991 TIL 2009 (AKM) 1991 to 2009
funk_timeant numeric value Personens samlede antal arbejdstimer i året. 2008 to 2024
nace character code Branche for væsentligste beskæftigelse, fra 1992 til 2007 (AKM) 1992 to 2007
nacea character code Branchegruppering for arbejdssted (1993 til 2007) (AKM) 1992 to 2007
nacea_db07 character code Branchegruppering for arbejdssted ( fra 2007) (AKM) 2007 to 2024
nacei character code Branchekode for selvstændige og medarbejdende ægtefællers virksomhed(1993 til 2007) (AKM) 1993 to 2007
nacei_db07 character code Branchegruppering for indehaver (Selvstændig eller medhjælpende ægtefælle) (fra 2007) (AKM) 2007 to 2024
nace_13 character code Branche for væsentligste beskæftigelse, fra 1993 til 2007 (AKM) 1993 to 2007
nace_db07 character code Branche for væsentligste beskæftigelse, fra 2008-2013 (AKM) 2007 to 2013
nystgr character code Stillingsgruppering 1980 til 1995 (AKM) 1980 to 1999
omfang character code Omfang af skattepligt 1991 to 2024
senr character code SE-nummer 1985 to 2002
senri character code SE-nummer for den virksomhed som personen ejer 1985 to 2002
senrl character code SE-nummer for lønmodtager 1985 to 1998
typ character code Stillingstype 1980 to 1999
version character code Moduldata version 1991 to 2024
virkf numeric value Virksomhedskode angiver hvilken form for ejerskab der er på den arbejdsplads personen får størst erhrvsindkomst fra (AKM) 2001 to 2013
virkfa numeric value Virksomhedskode angiver hvilken form for ejerskab der er på den arbejdsplads personen får størstklønindkomst/arbejdstimer (AKM) 2001 to 2024
virkf_13 numeric value Virksomhedskode angiver hvilken form for ejerskab der er på den arbejdsplads personen får størst erhrvsindkomst fra (AKM) 2001 to 2024
  • beskst13: A different question from socio13: where the money came from, rather than what the person’s labour market position was. A source does now exist (https://www.dst.dk/da/TilSalg/data-til-forskning/generelt-om-data/ dokumentation-af-data/hoejkvalitetsvariable/ Personers-tilknytning-til-arbejdsmarkedet-set-over-hele-aaret–AKM-/BESKST13, checked 2026-09-09), a large classification with its own PDF supplement for edge cases, linked rather than transcribed. beskst13 differs from beskst02 in named ways (net rather than gross income for the self-employed, price-adjusted thresholds), which DST calls a difference rather than a break: see beskst02’s reader_note for the sharper break, between beskst02 and the older beskst.
  • disco08_alle_indk_13: Occupation, not socioeconomic position. DISCO-08 only starts in 2010; 1991-2009 uses the older disco_alle_indk_13 with a different code set, so an occupation series across 2010 is not continuous.
  • nace_db07_13: Industry classification from 2007. The pre-2007 series uses nace_13, which is a different classification rather than a renamed one.
  • alder_ult_ink: Age at the end of the year, not at your index date. Recompute from a birth date if the exact age matters.
  • beskst: Not comparable with beskst02, in DST’s own words, not just a difference of degree. Source: https://www.dst.dk/da/TilSalg/data-til-forskning/ generelt-om-data/dokumentation-af-data/hoejkvalitetsvariable/ Personers-tilknytning-til-arbejdsmarkedet-set-over-hele-aaret–AKM-/BESKST02 (checked 2026-09-09). People with an unemployment share over 50 percent, and people on efterløn (early retirement pay), get their own codes under beskst02 that beskst does not have, and the rules for who counts as self-employed also changed. A study spanning 2001-2002 should not treat this as a relabelled continuation of the same variable.
  • beskst02: Not comparable with beskst (see beskst’s own reader_note): DST states this directly, not just a difference of degree. Comparable with beskst13 with named exceptions (net vs gross self-employment income, price adjustment); see beskst13’s reader_note.

No published source gives a data type for 46 of these 47 columns, so the Type column is our own assumption. Check with sapply(class) on a row of your own data before relying on it, especially for code columns, which lose their leading zeros if they arrive as numbers.

Join key: pnr.

Joins to other registers:

  • pnr joins to BEF (many-to-one).
Value sets for the coded columns (11)
Code system Values
socio13 11 Selvstændige, 110 Selvstændige, 111 Selvstændige erhvervsdrivende med 10 eller flere ansatte, 112 Selvstændige erhvervsdrivende med 5-9 ansatte, 113 Selvstændige erhvervsdrivende med 1-4 ansatte, 114 Selvstændige erhvervsdrivende uden ansatte, 12 Medarbejdende ægtefælle, 120 Medarbejdende ægtefælle, 13 Lønmodtagere, 131 Lønmodtagere med ledelsesarbejde, 132 Lønmodtager i arbejde der forudsætter færdigheder på højeste niveau, 133 Lønmodtager i arbejde der forudsætter færdigheder på mellemniveau, 134 Lønmodtager i arbejde der forudsætter færdigheder på grundniveau, 135 Andre lønmodtagere, 139 Lønmodtager uden nærmere angivelse, 21 Arbejdsløs mindst halvdelen af året, 210 Arbejdsløse mindst halvdelen af året, 22 Sygedagpenge, orlov mv., 220 Modtager af sygedagpenge, uddannelsesgodtgørelse, orlovsydelser mv., 31 Uddannelsessøgende, 310 Under uddannelse, inkl. skoleelever på min. 15 år, 32 Pensionist/efterløn, 321 Førtidspensionister, 322 Folkepensionister, 323 Efterlønsmodtagere mv., 33 Kontanthjælp, 330 Kontanthjælpsmodtagere, 41 Andre, 410 Andre, 42 Børn, 420 Børn under 15 år, ultimo året
beskst02 01 Selvstændig, 02 Medarbejdende ægtefælle, 03 Lønmodtager og ejer af virksomhed, 04 Lønmodtager, 05 Lønmodtager med understøttelse, 06 Pensionist og ejer af virksomhed, 07 Pensionist, 08 Øvrige, 09 Efterlønsmodtager, 10 Arbejdsløs mindst halvdelen af året (nettoledighed), 11 Modtager af dagpenge (aktivering og lign., sygdom, barsel og orlov), 12 Kontanthjælpsmodtager, 99 Ikke i AKM
disco08 Not listed here - see DST’s classification
nace_db07 Not listed here - see DST’s classification
beskst 01 Selvstændig, 02 Medarbejd., 03 Lønmodt. m. virksom., 04 Lønmodtager, 05 Lønmodtager med understøt., 06 Pensionist m. virksom., 07 Pensionist, 08 Øvrige, 99 Ikke i AKM
branche_77 Not listed here - see DST’s classification
disco_old Not listed here - see DST’s classification
discotyp 0 Uoplyst, 1 Stat, 2 Kommune, 3 A-kasse, 4 Privat virksomhed, mindst 10 ansatte, 5 CPR (1991-1999), 6 Foregående år, samme arbejdsgiver og arbejdssted (2004-), 7 Uddannelse igangværende, 8 A-kasse og branchekode, 9 Uddannelse afsluttet + branche, 10 Danmarks Statistiks e-indkomstregister
nace_old Not listed here - see DST’s classification
nystgr Not listed here - see DST’s classification
omfang 0 Børn under 15 år og uden indkomst og formue (1998-2001), 1 Fuldt skattepligtig og har bopæl både primo og ultimo året, 2 Har ikke boet i Danmark hele året, eller er død i løbet af året, 3 Findes i oplysningsseddelregisteret men ikke i slutligningsregisteret (fra 2002), 4 Personer under 15 år uden indkomst, samt personer der ikke er skattepligtige, 5 Er død (bobehandlingskode) og ingen indkomst i slutligningsregisteret, 6 Indkomst usandsynlig for mindst en person i familien, kan ikke rettes konsistent
  • socio13: Two codes are easy to misread. 410 is Andre (other), not unemployed: the unemployed are 210. And 420 is children under 15, a known category rather than a missing value, so it appearing in an adult cohort means the index date is wrong rather than the data being incomplete.
  • beskst02: Not comparable with beskst (see beskst’s own reader_note): DST states this directly, not just a difference of degree. Comparable with beskst13 with named exceptions: self-employment income is measured net of capital income in beskst13 rather than gross, and beskst13’s amount thresholds are price-adjusted where beskst02’s are not. A study spanning both should read DST’s own change note before treating them as one continuous series.
  • disco08: The AKM columns do not draw purely from this file. Checked against disco08_alle_indk’s own value list on DST’s high-quality variable page: only 564 of its 790 distinct codes appear in this CSV’s 564 level-5 codes. disco_typ (see discotyp.yaml) explains why: the occupation code for a given person-year can come from several source registers of varying vintage and quality, including imputation, so a study will see codes this file’s current edition does not carry. Do not treat a code missing from this CSV as an error in the data before checking discotyp.
  • nace_db07: Two things to check before using this as a lookup. First, format: this file writes the detailed code with dots (01.11.00); nace_db07 and nace_db07_13 hold it without them (011100). Second, coverage: checked against nace_db07’s own value list on DST’s high-quality variable page, only 490 of its 743 distinct codes match this file’s 738 level-2 codes even after stripping dots. As with DISCO-08 (see disco08.yaml), the industry code for a given person-year can be sourced from more than one register, so a code absent from this CSV is not necessarily an error.
  • beskst: Not comparable with beskst02, in DST’s own words, not just a difference of degree: people with an unemployment share over 50 percent, and people on efterløn (early retirement pay), get their own codes under beskst02 that this code list does not have, and the rules for who counts as self-employed also changed. See beskst02’s reader_note.
  • branche_77: Superseded by NACE (see nace), which the AKM register also carries for overlapping years. A study reaching back before 1992 needs this code list; one starting later should prefer NACE or DB07 rather than reading a code DST had already retired.
  • disco_old: Do not read a code here against DISCO-08’s published list (disco08.yaml): the two classifications share the general numeric shape but DST revised the detail at the 2010 switch, and a code that means one occupation in DISCO-08 is not guaranteed to mean the same thing, or to exist at all, in the pre-2010 scheme.
  • discotyp: A different question from the DISCO occupation code itself: this says where that code came from, not what the job was. DST’s own page states that DISCO code quality is best when discotyp is 1, 2, 4 or 10, and that the remaining codes mean the DISCO code was set by imputation.
  • nace_old: Do not read a code here against DB07/NACE Rev.2’s published list (nace_db07.yaml): the 2007-2008 revision changed the code structure, and a code that means one industry under DB07 is not guaranteed to mean the same thing, or to exist at all, under this older scheme.
  • nystgr: Retired in 1995 and replaced by DISCO. A code’s meaning can shift within the window a study covers: DST’s own page notes that code 5100 changed meaning in 1992 (the group it now names used code 5500 before that year), so a series spanning 1992 needs the year-by-year note on the source page, not just the current label.
  • omfang: Code 2 changed meaning at the 2002 boundary: before 2002 (and again 2002-2009) it also absorbed children under 15 with no income or wealth, a group that codes 0 and 4 cover separately in other years. Code 5 (died, not settled) only exists from 2002; before that, a death with no settled income was coded 2 instead. DST’s own publications and statistikbanktabeller are restricted to omfang=1: an analysis that does not filter on it silently includes partial-year residents, the newly dead, and unsettled records alongside ordinary full-year taxpayers.

Where these values come from:

Worth knowing:

  • socio13: This is the version to use. It runs from 1991, so it reaches back further than its name suggests and covers the periods of the three older versions as well.
  • socio02: Uses socio13’s lookup, but the two do not fully agree. Checked 2026-09-09 against DST’s own value tables (https://www.dst.dk/da/TilSalg/ data-til-forskning/generelt-om-data/dokumentation-af-data/hoejkvalitetsvariable/ Personers-tilknytning-til-arbejdsmarkedet-set-over-hele-aaret–AKM-/SOCIO02): code 111 here is “10 or more employees”, the same boundary socio13 uses, so socio02 and socio13 read together safely. socio (the 1994-2001 predecessor) is the one that disagrees: see its own reader_note.
  • socio: Uses socio13’s lookup, but the two do not agree on code 111. Checked 2026-09-09 against DST’s own value tables (https://www.dst.dk/da/TilSalg/ data-til-forskning/generelt-om-data/dokumentation-af-data/hoejkvalitetsvariable/ Personers-tilknytning-til-arbejdsmarkedet-set-over-hele-aaret–AKM-/SOCIO): here, 111 is “selvstaendig med 50 eller flere ansatte” (self-employed, 50+ employees). In socio02 and socio13, the same code 111 is “10 eller flere ansatte” (10+ employees). The size boundary moved and the code did not change, so a self-employed person with, say, 20 employees is 111 in one era and a different code in the other, with nothing in the data to flag the switch.
  • year: Not a DST variable. It comes from fastreg’s parquet conversion, which concatenates the yearly deliveries, so it exists in the data you read but not in DST’s own documentation of this register.

SEPLINE categorisation of socio13:

  • Employed: 110–114, 120, 131–135, 139
  • Student: 310
  • Unemployed: 210, 410
  • Outside labour market: 220, 321, 330
  • Retired: 322, 323
  • Unknown: 0, 420 or missing

9. Project-specific registers

Many projects have access to registers beyond the standard list above - e.g. quality registers from clinical databases or pre-computed classification files.

These are project-specific and not available in all projects on DST.

Examples are private hospitals (priv_adm, priv_diag, priv_skspor - structured in parallel with LPR) and various clinical quality registers. Availability varies from project to project.

Working on DARTER / project 708421?

The project uses among others DBSO (the Danish Obesity Treatment Database) and OSDC (Open Source Diabetes Classifier).

Data resource profiles and reporting

Data resource profiles are the papers you cite when you describe a register in your methods section: they document the register’s content, coverage and validity. Cite the profile for each register you use.

Register Data resource profile
The Danish health-care system and epidemiological research (overview) Schmidt et al. 2019, Clin Epidemiol - doi:10.2147/CLEP.S179083
CPR (Civil Registration System) Schmidt, Pedersen & Sørensen 2014, Eur J Epidemiol - doi:10.1007/s10654-014-9930-3
LPR (National Patient Registry) Schmidt et al. 2015, Clin Epidemiol - doi:10.2147/CLEP.S91125
LMDB (Prescription Registry) Pottegård et al. 2017, Int J Epidemiol - doi:10.1093/ije/dyw213
Cause of Death Register Helweg-Larsen 2011, Scand J Public Health - doi:10.1177/1403494811399958

Reporting: report observational studies following STROBE. For register-based / routinely-collected-data studies, RECORD extends STROBE, and RECORD-PE covers pharmacoepidemiology specifically - see RECORD-PE (EQUATOR Network).

Back to top