Drugs and formularies

FDA NDC Directory (drug product dimension)

drug_silver.dim_drug·live·dim·weekly·Drug Product Catalog (NDC)
Rows
N/A
Columns
38
History
2026-05-15 to 2026-06-01
Card
yesgrain, traps, filters
Typed tools
2

What it is

  1. 1The FDA NDC Directory drug master (package-level catalog) for the cost-data platform — one row per NDC-11 package per weekly snapshot — providing the canonical drug identity and descriptors (names, labeler, form/route, approval pathway, DEA schedule, pharm class) that all drug-cost fact tables join to via ndc11.

Grain

KeyGrain
ndc11observed_period
  1. 1One row per drug package (NDC-11) per weekly FDA-NDC-Directory snapshot.
  2. 2Verified: ndc11 x observed_period = 642,379 distinct = 642,379 total rows.
  3. 3The table currently holds 3 full snapshots (2026-05-15, 2026-05-25, 2026-06-01); within any single snapshot ndc11 (equivalently package_ndc) is unique. ndc11 alone is NOT unique across the table (214,924 distinct ndc11 but 642,379 rows — ~3 snapshot copies each).

How to read it

  1. 1Resolve a drug's identity/attributes and join it to cost data.
  2. 2Example (current GLP-1 packages with their identity, ready to join to ASP/price facts): SELECT ndc11, proprietary_name, nonproprietary_name, labeler_name, dosage_form_name, route_name, marketing_category_name, package_description FROM drug_silver.dim_drug WHERE observed_period = (SELECT MAX(observed_period) FROM drug_silver.dim_drug) AND nonproprietary_name IN ('tirzepatide','semaglutide').
  3. 3Answers 'what packages/NDCs exist for this drug, who makes them, and what is their FDA identity' — then join ndc11 to fact_drug_asp_quarterly / fact_drug_consumer_price / fact_part_d_plan_drug_pricing to attach prices.
  4. 4Always pin to one snapshot via observed_period (do NOT use is_current).

Traps

  1. 1is_current is useless for dedup: ALL 642,379 rows have is_current=true (no false rows exist yet). To get a single current view you MUST filter on a snapshot date, e.g. WHERE observed_period = (SELECT MAX(observed_period) FROM dim_drug). Treating is_current=true as 'the latest' returns ~3x duplicate NDCs.
  2. 2ndc11 is NOT unique table-wide — it repeats once per weekly snapshot (214,924 distinct ndc11 vs 642,379 rows). Any join on ndc11 alone fans out ~3x; always pair ndc11 with a snapshot filter (the true grain is ndc11 x observed_period).
  3. 3Three columns are 100% NULL across every row and look like real fields but carry no data: active_numerator_strength, active_ingred_unit, and drug_source_version_id. Do not rely on them for strength/units — strength is only available inside the package_description free-text (and richer detail lives in dim_drug_label / dim_orange_book_product).
  4. 4start_marketing_date and end_marketing_date are STRINGS in YYYYMMDD format, not DATE types — cast before comparing. start_marketing_date uses '19000101' as a sentinel for old/unknown dates. end_marketing_date is ~97.5% NULL, and NULL means 'still actively marketed' (not missing); is_active is always true so it cannot flag discontinued packages — use a non-null end_marketing_date or cross-snapshot disappearance instead.
  5. 5This is the drug spine/master only (package identity + descriptors). It contains NO prices. Drug cost lives in sibling fact tables in drug_silver (fact_drug_asp_quarterly, fact_drug_acquisition_cost, fact_drug_consumer_price, fact_drug_va_fss_price, fact_drug_medicaid_rebate_product, fact_part_d_plan_drug_pricing, fact_drug_formulary, etc.), which you join back to this table on ndc11. Deeper FDA label/approval/patent attributes live in dim_drug_label, dim_drug_application, dim_orange_book_product, and dim_purple_book_product — not here.
  6. 6Snapshots are point-in-time, not SCD2 ranges: effective_period_start == effective_period_end == observed_period == asserted_at for every row (single-day). Across the 3 snapshots ~1,145 NDCs were added between 2026-05-15 and 2026-06-01, so the NDC universe grows week to week — pick a snapshot deliberately when reproducing results.

Columns (38)

ColumnTypeMeaning
ndc11stringCanonical 11-digit National Drug Code, zero-padded, no dashes (the package-level drug identifier). VERIFIED = labeler_code(5) + product_code(4) + package_code(2) concatenated (0 mismatches). This is the primary join key to every fact_drug_* cost table. 214,924 distinct values; ~3 copies (one per snapshot).
labeler_codestringFirst NDC segment (5 chars) = FDA-assigned manufacturer/labeler code. 5,354 distinct. Always 5 chars.
product_codestringSecond NDC segment (4 chars) = the product (drug formulation) within a labeler. 9,573 distinct.
package_codestringThird NDC segment (2 chars) = the specific package size/configuration of the product.
product_ndcstringProduct-level NDC in dashed format, e.g. '0002-0152' (labeler-product, no package segment). 112,469 distinct products in latest snapshot vs 214,474 packages. One ndc11 maps to exactly one product_ndc. Use this to roll packages up to the product.
package_ndcstringFull package-level NDC in FDA dashed format, e.g. '0002-0152-01'. 1:1 with ndc11 (same identity, dashed presentation). 214,924 distinct.
is_activebooleanBoolean. TRAP: it is TRUE for 100% of rows in every snapshot — the FDA NDC Directory file lists currently-marketed finished products, so this is effectively a constant, not a useful filter. To find discontinued packages use end_marketing_date instead, or compare across snapshots.
proprietary_namestringBrand / trade name, e.g. 'Zepbound', 'Humulin'. Always populated (0 null).
nonproprietary_namestringGeneric / nonproprietary name, e.g. 'tirzepatide', 'Insulin human'. Always populated (0 null).
dosage_form_namestringFDA dosage form, e.g. 'INJECTION, SOLUTION', 'TABLET'. 137 distinct forms. Always populated.
route_namestringRoute of administration, e.g. 'SUBCUTANEOUS', 'ORAL' (top route, ~140K), 'TOPICAL', 'INTRAVENOUS'. 192 distinct; multi-route combos use '; ' delimiter (e.g. 'INTRADERMAL; PERCUTANEOUS; SUBCUTANEOUS'). ~1% null.
marketing_category_namestringFDA marketing/approval pathway: ANDA (generic, ~107K, the plurality), OTC MONOGRAPH DRUG, UNAPPROVED HOMEOPATHIC, NDA (brand new drug), BLA (biologic), NDA AUTHORIZED GENERIC, EMERGENCY USE AUTHORIZATION, etc.
application_numberstringFDA submission identifier with a pathway prefix that mirrors marketing_category_name: ANDA##### (generic), NDA##### (new drug), BLA##### (biologic), M###/part### (OTC monograph citations). ~15% null in latest snapshot — OTC-monograph and homeopathic products often have none.
labeler_namestringManufacturer / labeler name, e.g. 'Eli Lilly and Company'. 7,726 distinct in latest snapshot. Always populated.
substance_namestringActive ingredient(s), UPPERCASE; combination drugs delimit multiple actives with '; ' (e.g. 'TROSPIUM CHLORIDE; XANOMELINE' for Cobenfy). ~1.3% null.
active_numerator_strengthstringDEAD COLUMN — 100% NULL across all 642,379 rows. Exists in schema but never populated; the silver build does not split strength out. Get strength from package_description text or downstream tables.
active_ingred_unitstringDEAD COLUMN — 100% NULL across all 642,379 rows. Companion to active_numerator_strength, also never populated.
pharm_classesstringFDA Established Pharmacologic Class string(s), comma-separated with bracketed type tags: [EPC] established class, [MoA] mechanism of action, [CS] chemical structure, [PE] physiologic effect. ~34% null (homeopathic/OTC monograph products often lack a class).
dea_schedulestringDEA controlled-substance schedule: NULL = non-controlled (~95% of rows / 202,889), else CII / CIII / CIV / CV. NULL is meaningful (= not a controlled substance), not missing data.
product_type_namestringFDA product type: HUMAN PRESCRIPTION DRUG (~118K), HUMAN OTC DRUG (~91K), NON-STANDARDIZED ALLERGENIC, PLASMA DERIVATIVE, STANDARDIZED ALLERGENIC, VACCINE, CELLULAR THERAPY.
package_descriptionstringFree-text human-readable package contents incl. quantities and unit sizes, e.g. '1 VIAL, SINGLE-DOSE in 1 CARTON (0002-0152-01) / .5 mL in 1 VIAL, SINGLE-DOSE'. This is where pack size / unit strength effectively lives (since the strength columns are null).
start_marketing_datestringDate the package began marketing. STRING in YYYYMMDD format (length always 8), NOT a date type. Range 19000101 (sentinel/placeholder for very old/unknown) to 20260529. Parse/cast before date math.
end_marketing_datestringDate marketing ends/ended, STRING YYYYMMDD. ~97.5% NULL — NULL is meaningful: package is still actively marketed with no scheduled end. A non-null value (e.g. '20261215') indicates a planned/known discontinuation.
observed_perioddateSnapshot date = the day this FDA NDC Directory file was ingested. One of 3 values (2026-05-15, 2026-05-25, 2026-06-01). Part of the grain key. Equal to asserted_at, effective_period_start, and effective_period_end for the same row.
asserted_atdateWhen this snapshot's facts were asserted; identical to observed_period (1:1 with the snapshot). Redundant with observed_period.
effective_period_startdateStart of the row's validity window; equals the snapshot date and equals effective_period_end (single-day, point-in-time snapshot — this is NOT a true SCD2 range). Profiler's chosen time column; interchangeable with observed_period as the snapshot key.
effective_period_enddateEnd of validity window; equals effective_period_start for every row (no open-ended or multi-day ranges). Confirms snapshot, not range, semantics.
cms_vintage_sequenceintVintage sequence integer; constant value 1 for all rows (not a useful discriminator here).
parse_revisionintParser revision number; constant 1 for all rows.
parser_artifact_hashstringSHA-256 of the parser artifact used to build the snapshot. 3 distinct values (one per snapshot). Provenance/lineage.
source_urlstringOrigin URL of the raw file; single constant value 'https://www.accessdata.fda.gov/cder/ndctext.zip' (FDA NDC Directory zip).
sha256_content_hashstringSHA-256 of the raw source file content; 3 distinct values, 1:1 with the snapshot (changes week to week as FDA updates the file). Provenance/dedup key.
source_idstringLogical source identifier; single constant 'fda_ndc_directory'. Confirms the whole table is sourced solely from the FDA NDC Directory.
is_currentbooleanBoolean is-current flag. MAJOR TRAP: TRUE for 100% of rows (all 3 snapshots), so it does NOT isolate the latest snapshot. Do not filter on is_current to dedup — use MAX(observed_period) or the specific snapshot date instead.
bronze_object_keystringS3 key of the bronze raw object backing the snapshot, e.g. 'drug/bronze/fda_ndc_directory/2026-06-01/0776ac0c...-ndctext.zip'. 3 distinct, 1:1 with snapshot; the date is embedded in the path.
s3_version_idstringS3 object version id of the bronze file; 3 distinct (one per snapshot). Lineage.
vintage_tagstringVintage label; constant literal 'none' for all rows (unused).
drug_source_version_idstringDEAD COLUMN — 100% NULL across all 642,379 rows. Intended cross-source version linkage but never populated.

Query it

describe_data_source(source_fqn="drug_silver.dim_drug")     # the card, live
query_substrate(sql="SELECT * FROM drug_silver.dim_drug WHERE ndc11 = '<value>' AND observed_period = '<value>' LIMIT 100")
ItemValue
Typed tools that read itira_mfp_exposure, recall_spend_window
Identity keyndc11
Joinhow_to_join(source_fqn="drug_silver.dim_drug")
Raw doorAthena (read-only via query_substrate): drug_silver.dim_drug
NoteIceberg table drug_silver.dim_drug. Runner: pipelines/drug/ingest/fda_ndc_directory_runner.py.

This page as markdown: /docs-md/data/drug_silver_dim_drug.md · every page in one file: /llms-full.txt