← Methods repository
concept

Linked Multi-Database Study (Record Linkage)

A study design that joins records for the same individuals across two or more separately maintained data sources (e.g., claims, EHR, disease registry, vital records) via deterministic or probabilistic record linkage to assemble a single analysis cohort with broader coverage of exposures, covariates, and outcomes than any source alone.

Study_Designdata-linkagerecord-linkageprobabilistic-linkagedeterministic-linkageseer-medicaremulti-databaselinkage-errorstudy-design
Methods reference only. Use primary source citations and local policy before applying this in a study protocol, regulatory submission, payer dossier, or clinical decision.

In plain language

A linked multi-database study joins records for the same person from two or more separate data sources — for example, a cancer registry plus Medicare claims plus a death registry — so researchers can answer questions that no single source could answer alone. Think of it as taking a jigsaw puzzle where one piece holds the diagnosis, another holds the prescriptions, and a third holds the date of death, and fitting them together into one complete picture for each patient. The catch is that not every patient can be matched across all sources, so the final study cohort is only the linkable subset — and if the patients who failed to match differ in important ways, results may not apply to everyone.

A linked multi-database study builds its analytic cohort by matching records for the same person across two or more independently collected data sources and then analyzing the combined longitudinal record. Linkage is the data-engineering step that precedes any design or estimation choice: it does not by itself confer causal validity, but it changes which variables are observable (severity from EHR, dispensings from claims, death from vital records, stage/grade from a registry) and therefore which questions are answerable and which biases can be addressed. The classic exemplars are SEER-Medicare (cancer registry linked to Medicare claims) and the population-wide linkage systems of Western Australia, Scotland, and the Nordic countries, where a stable personal identifier joins essentially the whole population across health and administrative registers.

Core conceptual distinction

Linkage methods sit on a spectrum from deterministic to probabilistic. Deterministic linkage joins records that agree exactly (or after standardization) on a set of identifiers — ideally a single trusted unique ID (a national/beneficiary number), or a rule-based match on combinations of name, sex, date of birth, and ZIP. It is transparent and reproducible but brittle: any error or change in an identifier (a misspelled surname, a transposed birth date, a remarriage) drops a true pair (a missed match, false negative). Probabilistic (Fellegi–Sunter) linkage scores each candidate record pair on partial agreement across multiple fields, weighting each field by how discriminating it is (m-probability: agreement among true matches; u-probability: chance agreement among non-matches) and accepting pairs above a threshold. It recovers true pairs that deterministic rules miss but admits false matches (linking two different people) and requires threshold calibration and clerical review of the gray zone. The estimand-relevant point is subtle but decisive: linkage error is a measurement/selection problem, not random noise. Missed and false matches that depend on exposure, outcome, age, or data quality bias effect estimates in a direction that is hard to sign without a clerical-review gold standard or a linked/unlinked sensitivity analysis. "Linked data" is therefore not a single method but a substrate whose quality (match rate, precision, and differential error) must be reported and probed exactly like any other source of misclassification.

Pros, cons, and trade-offs

- vs a single claims database: Linking claims to EHR adds clinical depth (labs, vitals, smoking, severity, free-text diagnoses) that claims lack, sharpening confounder control and outcome validation; linking to vital records firms up the most consequential censoring event (death). Cost: you analyze only the linkable subset, which is rarely a random sample of either source (linkage selection bias), and you inherit two coding systems, two date conventions, and two sets of missingness. Prefer linkage when an unmeasured confounder or an unobservable outcome lives in the other source and the linkable subset is large and demonstrably representative. - vs a single EHR system: Linking EHR to claims captures care delivered outside the health system (out-of-network visits, pharmacy fills, hospitalizations elsewhere), curing EHR's signature defect — incomplete capture when patients seek care across systems. Cost: claims add billing-driven coding noise and lag. Prefer linkage whenever leakage out of the EHR is plausible (most real populations). - vs deterministic-only linkage: Probabilistic linkage raises sensitivity (fewer missed matches) at some cost to precision and reproducibility, and it surfaces an explicit, auditable uncertainty about each pair. Prefer probabilistic when identifiers are imperfect or no single trusted ID exists; prefer deterministic when a high-quality unique ID is available and false matches are the dominant concern (e.g., mortality outcomes). - vs collecting de novo primary data: Linkage is faster and cheaper at population scale and avoids recall bias. Cost: you are constrained to variables that were already recorded for other purposes, and you cannot fix a missing identifier after the fact. Prefer linkage for large comparative safety/effectiveness and HEOR questions; commission primary collection only for variables no existing source holds.

When to use

A key confounder, exposure, covariate, or outcome is reliably recorded in source B but absent or poorly captured in source A (registry stage + claims treatment + vital-records death is the archetype); validation of a claims- or EHR-based phenotype against a gold-standard source; capturing care that crosses system boundaries; assembling sufficient person-time for rare exposures or outcomes by pooling. A defensible study reports the match rate, the linkage method and identifiers, an estimate of linkage precision, and at minimum an analysis restricted to high-confidence links versus the full linked set.

When NOT to use — and when it is actively misleading or dangerous

- The linkable subset is selected on something related to exposure or outcome. If linkage success depends on having a valid SSN/insurance ID, on survival to a registry update, or on care concentration, the linked cohort is a biased sample and effect estimates generalize to no real population. Linkage selection can masquerade as a treatment effect. - Differential linkage error by exposure or outcome. If sicker, older, or one-arm patients are systematically harder to link (more name changes, more facility transfers, earlier death before an ID is captured), missed matches are differential and bias the contrast. This is the linked-data analogue of differential misclassification and is not fixed by a larger N. - Treating a high match rate as proof of validity. A 95% match rate says nothing about precision — a few percent of false matches that attach the wrong outcome (e.g., another person's death) to an exposed patient can swamp a small true effect. Match rate and precision are different quantities. - No mechanism to estimate linkage error. Without a clerical-review sample, a known-truth subset, or a sensitivity analysis varying the match threshold, you cannot bound the bias and should not make causal claims from a borderline linkage. - Re-identification / privacy infeasibility. If governance forbids holding the identifiers needed for a defensible match, forcing a weak link is worse than not linking.

Data-source operational depth

- Claims (FFS vs MA): The strength is complete paid utilization across sites of care; the weakness is the absence of clinical detail and the FFS/MA visibility gap. In Medicare, Medicare Advantage enrollees generate little or no fee-for-service claim history, so claims-side variables and outcomes are effectively missing for MA person-time — a linked SEER-Medicare analysis that ignores this confuses MA enrollment with absence of events. Restrict to continuous Parts A/B (and D for drugs) FFS enrollment over the relevant window, or carry an explicit MA indicator and censor MA person-time. Differential competing risk of death by exposure in elderly claims means a registry/vital-records death link is essential to avoid counting a death-curtailed follow-up as event-free. - EHR: Adds labs, vitals, problem lists, and notes that validate phenotypes and capture severity, but visit-driven capture means a patient who seeks care elsewhere looks event-free. Linking to claims restores out-of-system events; the linkage itself must reconcile the EHR encounter/order date against the claims service/fill date before assigning index or outcome dates. - Registry: Best-in-class for adjudicated, clinically rich outcomes (cancer stage, grade, histology) and incidence, but typically lacks complete treatment and pharmacy exposure and updates on a lag. Linking to claims supplies the full treatment trajectory and to a death index firms up survival; registry update cycles can induce immortal-time-like artifacts if the linkage date, not the diagnosis date, is used as time zero. - Linked claims–EHR–registry–vital-records: The ideal substrate (severity + completeness + adjudicated outcomes + reliable mortality) but it concentrates every failure mode: linkage selection (only the linkable subset), order/fill/service date discrepancies that corrupt time-zero, two diagnosis coding systems to harmonize, and the need to reconcile conflicting values (a death date in vital records that postdates a claim). Resolve identifiers and dates before applying any design restriction, and run the analysis on both the high-confidence link set and the full set.

Worked claims example

Question: 1-year all-cause mortality after first-line systemic therapy for stage IV colorectal cancer, comparing regimen A vs regimen B, using a cancer registry linked to Medicare claims and the vital-records death index. (1) Linkage: the registry carries SSN, sex, date of birth, and ZIP; deterministically link to the Medicare enrollment file on the beneficiary ID where the registry-supplied SSN matches, then run a probabilistic pass on the residual unmatched registry records (partial agreement on DOB, sex, ZIP, last name) and clerically review pairs in the gray zone — record the per-source match rate and an estimated false-match rate from the review sample. (2) Cohort: keep patients with a registry stage IV colorectal diagnosis and continuous Medicare Parts A/B FFS enrollment (no MA-only spans) for 365 days before and through follow-up, so utilization is observable; index_date = date of first systemic-therapy claim (HCPCS J-codes) within 120 days of the registry diagnosis date — using the diagnosis date, not the registry-update date, prevents an immortal-time artifact. (3) Arm: assign regimen A vs B from the J-codes on the index claim. (4) Outcome: death within 365 days from the vital-records date (preferred over the claims-derived death indicator, which lags and misses out-of-hospital deaths); a few false matches here attach another person's death, so report the high-confidence-link result alongside the full-link result. (5) Censoring: disenrollment from FFS (including switch to MA), end of data, or 365 days, whichever first. (6) Sensitivity: repeat restricting to high-confidence (SSN-exact) links only, vary the probabilistic threshold, and compare the linked-only cohort's baseline characteristics to the full registry to probe linkage selection.

Worked example

Scenario

Suppose you want to study whether Drug A or Drug B leads to more deaths in the year after a cancer diagnosis. You have three sources: (1) a cancer registry with diagnosis dates, (2) a claims database with drug dispensing records, and (3) a death registry with dates of death. No single source contains all three pieces of information, so you link them. The table below shows five patients and which sources they appear in before and after linkage.

Dataset

Five patients across three sources before linkage. An X marks presence in that source.

patient_idin_cancer_registryin_claimsin_death_registrylinked_successfully
PT-001YesYesYesYes
PT-002YesYesNoYes
PT-003YesNoNoNo — missing from claims (uninsured or out-of-network)
PT-004YesYesYesYes
PT-005YesYesNoYes

Steps

  • Step 1 — Deterministic pass: try to match each registry patient to a claims record using an exact Social Security number. PT-001, PT-002, PT-004, and PT-005 all have a clean SSN match; PT-003 has no claims record at all (perhaps uninsured) and cannot be linked.

  • Step 2 — Probabilistic pass (if needed): for any registry patient whose SSN is missing or mistyped, score candidate claims records on partial agreement across date of birth, sex, and ZIP code. A high enough score earns acceptance; a borderline score goes to clerical review; a low score is rejected as a non-match.

  • Step 3 — Attach the death registry: once registry-claims pairs are confirmed, join the death registry by SSN or name-DOB-sex combination. PT-001 and PT-004 have a death record; PT-002 and PT-005 do not (alive or died outside the registry's coverage).

  • Step 4 — Recognize the linkable subset: only the four patients who appear in both the registry and claims form the analysis cohort. PT-003 is excluded. If uninsured patients (like PT-003) are more likely to receive Drug A or to die, excluding them biases the Drug A vs Drug B comparison — this is linkage-selection bias.

  • Step 5 — Sensitivity check: compare the baseline characteristics (age, stage, comorbidities) of the four linked patients against the full five-patient registry. If PT-003 looks very different from the rest, generalizability is limited and the study report must say so.

Result

The linked cohort contains 4 of 5 registry patients (80% match rate). Of these 4, 2 have a confirmed death within 1 year (PT-001 and PT-004). The match rate looks acceptable, but PT-003's exclusion is a structural caveat: if unlinked patients share characteristics with one treatment arm, the effect estimate is biased in a direction that a larger sample cannot fix.

Runnable example

python implementation

Deterministic + probabilistic record linkage to build a linked study cohort. Required inputs (already cleaned, de-duplicated within source, and identifier fields standardized: upper-cased name, stripped suffixes, zero-padded ZIP): reg : registry records ->...

import numpy as np
import pandas as pd

ACCEPT_HI = 8.0   # accept probabilistic pairs at/above this match weight (clerical-review threshold above this)
ACCEPT_LO = 3.0   # below this, reject; [LO, HI) is the gray zone flagged for clerical review

def link_cohort(reg: pd.DataFrame, enr: pd.DataFrame) -> pd.DataFrame:
    # ---- Pass 1: deterministic on trusted unique ID (SSN). Highest precision. ----
    exact = (reg.dropna(subset=["ssn"])
                .merge(enr.dropna(subset=["ssn"])[["bene_id", "ssn"]], on="ssn", how="inner"))
    exact = exact[["reg_id", "bene_id"]].assign(tier="exact_id", match_weight=np.inf)

    # ---- Pass 2: probabilistic (Fellegi-Sunter) on registry records not matched in pass 1. ----
    # Field-level agreement weights = log2(m/u); m = P(agree | true match), u = P(agree | non-match by chance).
    weights = {  # illustrative, agreement-only weights; estimate m/u from a reviewed training sample per refresh
        "last_name": np.log2(0.90 / 0.005),
        "dob":       np.log2(0.95 / 0.0003),
        "sex":       np.log2(0.99 / 0.50),
        "zip5":      np.log2(0.80 / 0.001),
    }
    resid = reg[~reg["reg_id"].isin(exact["reg_id"])].copy()
    # Block on birth-year to keep pairwise comparison tractable on large files.
    resid["byear"] = resid["dob"].dt.year
    enr = enr.copy(); enr["byear"] = enr["dob"].dt.year
    pairs = resid.merge(enr, on="byear", suffixes=("_r", "_e"))

    score = np.zeros(len(pairs))
    score += np.where(pairs["last_name_r"] == pairs["last_name_e"], weights["last_name"], 0.0)
    score += np.where(pairs["dob_r"]       == pairs["dob_e"],       weights["dob"],       0.0)
    score += np.where(pairs["sex_r"]       == pairs["sex_e"],       weights["sex"],       0.0)
    score += np.where(pairs["zip5_r"]      == pairs["zip5_e"],      weights["zip5"],      0.0)
    pairs["match_weight"] = score

    # Keep the single best candidate per registry record, then apply thresholds (1:1 linkage).
    best = pairs.sort_values("match_weight", ascending=False).groupby("reg_id", as_index=False).first()
    best["review"] = (best["match_weight"] >= ACCEPT_LO) & (best["match_weight"] < ACCEPT_HI)
    prob = (best[best["match_weight"] >= ACCEPT_HI][["reg_id", "bene_id"]]
                .assign(tier="probabilistic"))
    prob = prob.merge(best[["reg_id", "match_weight"]], on="reg_id")

    links = pd.concat([exact, prob], ignore_index=True)
    return links[["reg_id", "bene_id", "tier", "match_weight"]]
r implementation

Deterministic + probabilistic record linkage with data.table. Inputs mirror the Python version (standardized identifiers, de-duplicated within source): reg : reg_id, ssn (NA-able), last_name, dob (Date), sex, zip5 enr : bene_id, ssn (NA-able), last_name,...

library(data.table)

ACCEPT_HI <- 8.0   # accept probabilistic pairs at/above this match weight
ACCEPT_LO <- 3.0   # [ACCEPT_LO, ACCEPT_HI) = gray zone for clerical review

link_cohort <- function(reg, enr) {
  setDT(reg); setDT(enr)

  # Pass 1: deterministic exact match on the trusted unique ID (SSN).
  exact <- merge(reg[!is.na(ssn), .(reg_id, ssn)],
                 enr[!is.na(ssn), .(bene_id, ssn)], by = "ssn")[
                 , .(reg_id, bene_id, tier = "exact_id", match_weight = Inf)]

  # Pass 2: probabilistic (Fellegi-Sunter) on registry records not matched above.
  w <- c(last_name = log2(0.90 / 0.005), dob = log2(0.95 / 0.0003),
         sex = log2(0.99 / 0.50),        zip5 = log2(0.80 / 0.001))
  resid <- reg[!reg_id %in% exact$reg_id]
  resid[, byear := year(dob)]; enr[, byear := year(dob)]

  # Block on birth-year to bound the number of candidate pairs.
  pairs <- merge(resid, enr, by = "byear", suffixes = c("_r", "_e"), allow.cartesian = TRUE)
  pairs[, match_weight :=
          (last_name_r == last_name_e) * w["last_name"] +
          (dob_r       == dob_e)       * w["dob"] +
          (sex_r       == sex_e)       * w["sex"] +
          (zip5_r      == zip5_e)      * w["zip5"]]

  # Best candidate per registry record, then threshold (1:1).
  setorder(pairs, -match_weight)
  best <- pairs[, .SD[1L], by = reg_id]
  best[, review := match_weight >= ACCEPT_LO & match_weight < ACCEPT_HI]
  prob <- best[match_weight >= ACCEPT_HI, .(reg_id, bene_id, tier = "probabilistic", match_weight)]

  rbindlist(list(exact, prob), use.names = TRUE)[, .(reg_id, bene_id, tier, match_weight)]
}