RxNorm–NDC Crosswalk
Pharmacy claims data is coded in NDC — a package-level identifier. Drug analytics typically requires concept-level grouping. The RxNorm–NDC crosswalk is the bridge: it maps every NDC to its corresponding RxNorm concept (RXCUI), enabling joins between claims data and the full drug hierarchy.
Why the Mapping is Necessary
NDC and RxNorm operate at different levels of specificity and serve different purposes:
NDC identifies
A specific physical package
NDC 00071021340 identifies exactly one product: a 90-count bottle of atorvastatin 10 mg oral tablets manufactured by a specific labeler. A different bottle size from the same manufacturer is a different NDC.
RxNorm identifies
A clinical concept
RXCUI 617314 identifies the concept “Atorvastatin 10 MG Oral Tablet” — regardless of manufacturer, package size, or labeler. Hundreds of NDCs may map to this single RXCUI.
Without the crosswalk, a query for “all atorvastatin 10 mg claims” would require knowing every NDC for that drug — an impractical and ever-changing list. With the crosswalk, you join on RXCUI and get all NDCs automatically.
Many NDCs → One RXCUI
The relationship is many-to-one: dozens or hundreds of NDCs map to a single SCD-level RXCUI. Sources of NDC multiplicity include different manufacturers (generics), package sizes (30-count vs 90-count), package types (bottle vs blister), and labeler variations (repackagers).
Six NDCs for atorvastatin 10 mg — multiple manufacturers and package sizes — resolve to two RXCUIs (generic SCD and branded SBD).
| NDC11 | drug_id (RXCUI) | Drug Name |
|---|---|---|
| 00071021340 | 617314 | Atorvastatin 10 MG Oral Tablet |
| 00071021390 | 617314 | Atorvastatin 10 MG Oral Tablet |
| 59762022201 | 617314 | Atorvastatin 10 MG Oral Tablet |
| 31722073090 | 617314 | Atorvastatin 10 MG Oral Tablet |
| 00071015614 | 617321 | Lipitor 10 MG Oral Tablet |
| 00071015616 | 617321 | Lipitor 10 MG Oral Tablet |
Join Patterns
1. Resolve an NDC from a claim to drug name and ingredient
SELECT
c.ndc,
d.drug_name,
d.ingredient,
d.dose_form,
d.is_generic
FROM claims c
JOIN ndc_rxnorm nr ON nr.ndc11 = c.ndc
JOIN rxnorm.drug_detail d ON d.drug_id = nr.drug_id;2. Roll up all NDC claims to ingredient level
SELECT
d.ingredient,
d.ingredient_rxcui,
COUNT(*) AS claim_count,
SUM(c.quantity) AS total_quantity
FROM claims c
JOIN ndc_rxnorm nr ON nr.ndc11 = c.ndc
JOIN rxnorm.drug_detail d ON d.drug_id = nr.drug_id
GROUP BY d.ingredient, d.ingredient_rxcui
ORDER BY claim_count DESC;3. Join claims to NADAC pricing (ingredient cost per claim)
SELECT
c.ndc,
d.drug_name,
c.quantity,
n.nadac_per_unit,
c.quantity * n.nadac_per_unit AS estimated_ingredient_cost
FROM claims c
JOIN ndc_rxnorm nr ON nr.ndc11 = c.ndc
JOIN rxnorm.drug_detail d ON d.drug_id = nr.drug_id
JOIN vw_nadac_latest n ON n.ndc = c.ndc;Common Edge Cases
NDC not in RxNorm
Newer products, OTC drugs, and some compounded formulations may not have an RXCUI mapping. These will produce NULL on a LEFT JOIN and must be handled explicitly in analytics pipelines.
Retired NDCs
NDCs for discontinued products may still appear in historical claims. RxNorm retains retired concepts with a status flag, so the mapping still works — but the drug_id should be treated carefully in active-drug analyses.
NDC format mismatch
Claims data often contains 10-digit or hyphenated NDCs. Always normalize to flat 11-digit before joining. See the NDC Normalization Guide for zero-padding rules.
Repackaged NDCs
A repackager may assign a new labeler code to the same drug. Both NDCs should map to the same drug_id in the crosswalk, but may show different labeler codes and pricing.
TwinFyRx ndc_rxnorm table
TwinFyRx maintains a fully normalized crosswalk in the ndc_rxnorm table, with both ndc11 (flat 11-digit) andndc9 (labeler + product) columns, plus labeler_code for labeler-level aggregations. Every row links to a drug_id (SCD/SBD RXCUI) which connects to the full drug hierarchy, enrichment layers, and NADAC pricing.