Drugs and formularies

FDA Drug Recalls (Enforcement Reports)

drug_silver.fact_drug_recall·live·silver·other (event-driven recalls; table itself is a single full-replace snapshot dated 2026-06-02, not a periodic time series). Recall events arrive roughly daily — by report_date the feed is continuous 2012-2026.·FDA Drug Recalls (Enforcement Reports)
Rows
N/A
Columns
45
History
2006-02-24 (earliest recall_initiation_date / effective_period_start; report_date history begins 2012-06-20) to 2026-05-27 (latest report_date; latest recall_initiation_date 2026-05-12) — data as of the single snapshot asserted_at 2026-06-02
Card
yesgrain, traps, filters
Typed tools
1

What it is

  1. 1A catalog of US FDA drug recall / enforcement events (openFDA Drug Enforcement feed, api.fda.gov/drug/enforcement.json), one row per recalled drug product, with the hazard classification, status, reason, recalling firm, geography, lifecycle dates, and sparse openFDA product enrichment.
  2. 2It is a drug-SAFETY reference table (not a cost/price table) used to flag whether a drug/lot/manufacturer has been recalled and how serious it was.

Grain

KeyGrain
recall_number
  1. 1One row per FDA drug recall (one unique recall_number). recall_number alone is the verified minimal key — 17,679 distinct values across 17,679 rows, zero duplicates. event_id groups multiple recalls into one enforcement action and is NOT the grain.

How to read it

  1. 1Find every active (not-yet-terminated) Class I (most serious) drug recall and what was wrong: SELECT recall_number, recalling_firm, product_description, reason_for_recall, recall_initiation_date FROM drug_silver.fact_drug_recall WHERE classification='Class I' AND status='Ongoing' ORDER BY recall_initiation_date DESC.
  2. 2Answers 'which serious drug recalls are currently open and why'.
  3. 3To check if a specific drug was ever recalled when openfda fields are null, also match product_description (it embeds brand/generic/NDC as text).

Traps

  1. 1recall_number is the ENTIRE grain by itself (0 duplicates, 17,679 distinct = 17,679 rows). The profiler's 10-column candidate key is a bloated SUPERSET — most of those extra columns (s3_version_id, bronze_object_key, source_id, drug_source_version_id, openfda_product_ndc_first) are either constants or 100% NULL and add nothing. Join/dedup on recall_number alone.
  2. 2openfda_product_ndc_first and drug_source_version_id are 100% NULL; cms_vintage_sequence, parse_revision (=1), vintage_tag (='none'), product_type (='Drugs'), source_id, source_url, sha256_content_hash, bronze_object_key, observed_period/asserted_at (=2026-06-02) are all CONSTANTS. None of these are usable join/filter keys despite some being flagged as 'candidate keys' — they're unique only because they're constant or null.
  3. 3This is a SINGLE full-replace snapshot, NOT SCD2 history: is_current=true for every row and there is exactly one asserted_at (2026-06-02). There is nothing to dedup and filtering is_current=true is a no-op. A later snapshot would replace the whole table, so do not expect to find superseded versions of a recall here.
  4. 4effective_period_end is BITEMPORAL, not the real recall end: it equals termination_date only for closed recalls; for the 2,883 Ongoing/Completed recalls with NULL termination_date it is back-filled to the snapshot date 2026-06-02. Using effective_period_end as 'when the recall ended' will be wrong for every open recall — use termination_date (and treat NULL as 'not yet terminated').
  5. 5Two date traps: (1) data_year = year(recall_initiation_date), NOT the year in the recall_number suffix (suffix matches only ~56%). (2) effective_period_start is an exact alias of recall_initiation_date. The four real FDA dates run init <= center_classification <= report <= termination; report_date is the best 'made public' date but only exists from 2012 onward, while initiation dates reach back to 2006.
  6. 6This is a drug-SAFETY/recall table, not a COST table. It is the openFDA Drug Enforcement feed (source_id='fda_drug_enforcement') and contains no prices — unlike its cost-bearing siblings in drug_silver (fact_drug_asp_quarterly, fact_drug_acquisition_cost, fact_drug_va_fss_price, fact_drug_spending_part_b/part_d). Use it to flag whether a drug/lot was recalled, not for pricing.
  7. 7Product/NDC identity is mostly trapped in free text: structured NDC is unusable (all NULL) and the openfda_* normalized fields (brand/generic/mfr/route/app#) cover only ~18% of rows (EPC only ~6%). For the other ~82% you must parse product_description / code_info text to get NDC, lot, manufacturer. recalling_firm is frequently a repackager/distributor (Aidapak, Attix, Cardinal), not the original labeler.

Columns (45)

ColumnTypeMeaning
recall_numberstringFDA recall identifier, e.g. 'D-1448-2014'. THE GRAIN KEY: globally unique, one row per value (17,679 distinct = 17,679 rows). Format is <product-prefix>-<sequence>-<year>. CAUTION: the 4-digit year suffix is the FDA cohort/case year and matches data_year only ~56% of the time (9,908/17,679) — do not treat the suffix as the recall year.
data_yearintInteger year. VERIFIED to equal year(recall_initiation_date) = year(effective_period_start) for 100% of rows — i.e. the year the firm initiated the recall, NOT the recall_number suffix year. Ranges 2006-2026; heavily back-loaded (2013+ is the bulk; 2006-2011 are a handful of stragglers).
event_idstringFDA enforcement-event id grouping related recalls. NOT unique — 17,679 recalls map to only 4,562 events. One event can span hundreds of recall_numbers (largest events: 470, 465, 382 recalls). Use to group a multi-product recall action; never as a row key.
classificationstringFDA recall severity (health-hazard) class. Exactly 3 values: 'Class II' (14,259, most common = could cause temporary/reversible harm), 'Class I' (1,727 = serious/death risk), 'Class III' (1,693 = unlikely to cause harm). Never null.
statusstringRecall lifecycle state. 3 values: 'Terminated' (14,793 = FDA closed it), 'Ongoing' (2,452 = still active), 'Completed' (434 = firm finished but FDA not yet terminated). Drives termination_date nullness (see gotchas).
voluntary_mandatedstringWho initiated. Almost always 'Voluntary: Firm initiated' (17,615); 'FDA Mandated' is rare (29); 35 nulls.
product_typestringCONSTANT 'Drugs' for every row — this table is the drug slice of FDA enforcement only. Carries no information; do not filter on it.
product_descriptionstringFree-text description of the recalled product: brand/generic name, strength, package/NDC, manufacturer & distributor. The richest product identifier in the table since structured NDC columns are unusable (see openfda_product_ndc_first). NDCs are often embedded here as text.
product_quantitystringFree-text amount recalled, e.g. '20 vials', '73,800 cups', '31,704 bottles'. Non-numeric/non-normalized; ~2,064 rows null (15,615 populated). Parse with care.
code_infostringFree-text lot numbers / expiration dates / product codes identifying the specific affected units. High-cardinality (14,042 distinct) but NOT unique and not a key.
distribution_patternstringFree-text geographic distribution scope, e.g. 'Nationwide', 'PA, CA', or a sentence listing states. Effectively always present (1 null).
reason_for_recallstringFree-text reason, e.g. 'Presence of Particulate Matter', 'Labeling: Label Mix-Up', 'Misbranded', 'cGMP Deviations'. 4,376 distinct values — descriptive, not coded.
recalling_firmstringName of the firm conducting the recall (1,629 distinct). Top firms are repackagers/compounders/distributors (Aidapak 538, Attix 470, King Bio 465, Cardinal Health 213), not just original manufacturers.
firm_citystringCity of the recalling firm. Free text.
firm_statestringUS state abbreviation of the recalling firm (49 distinct values present).
firm_countrystringCountry of the recalling firm. Overwhelmingly 'United States' (16,632); foreign firms exist (Canada 572, India 250, China 85, etc.).
firm_postal_codestringZIP/postal code of the recalling firm (often ZIP+4).
initial_firm_notificationstringHow the firm first notified customers: 'Letter' (9,003), 'Telephone' (2,706), 'Press Release' (2,571), a combined 'Two or more...' bucket (1,725), 'E-Mail', 'Other', 'FAX', 'Visit'; 279 null. Note 'E-Mail' and the legacy 'FAX' both appear.
observed_perioddateBitemporal: the snapshot/ingest date when these facts were observed. CONSTANT 2026-06-02 across ALL rows — the whole table is one snapshot. Not a recall date; do not use for recall timing.
asserted_atdateBitemporal assertion date = 2026-06-02 for every row (same single snapshot as observed_period). Provenance bookkeeping, not recall timing.
effective_period_startdateBitemporal validity start. VERIFIED IDENTICAL to recall_initiation_date for 100% of rows — it is an alias of the recall-initiation date. Range 2006-02-24 to 2026-05-12.
effective_period_enddateBitemporal validity end. Equals termination_date when the recall is terminated (14,796 rows), BUT when termination_date is NULL (2,883 Ongoing/Completed rows) it is set to the SNAPSHOT date 2026-06-02 (an open-ended 'still in effect as of snapshot' floor), NOT a real recall end. Never null. See gotchas.
cms_vintage_sequenceintProvenance vintage sequence. CONSTANT 1 — single ingested vintage. No information for analysis.
parse_revisionintParser revision number. CONSTANT 1 across all rows.
parser_artifact_hashstringSHA-256 of the parser artifact that produced the rows. Single constant value (one parser build).
source_urlstringOrigin API endpoint. CONSTANT 'https://api.fda.gov/drug/enforcement.json' — this table is openFDA Drug Enforcement (recall) data.
sha256_content_hashstringSHA-256 of the ingested source content (bronze object). Single constant value — the whole table came from one bronze file/snapshot.
source_idstringLogical source identifier. CONSTANT 'fda_drug_enforcement'.
is_currentbooleanSCD/current-flag. TRUE for 100% of rows — this is a full-replace snapshot with NO retained history. Filtering is_current=true is a harmless no-op; there are no is_current=false rows to dedup against.
bronze_object_keystringS3 key of the bronze source object (e.g. 'drug/bronze/fda_drug_enforcement/2026-06-02/...json'). Single constant value for the snapshot. Provenance only.
s3_version_idstringS3 object version id of the bronze file. Single constant value. Provenance only; the profiler mis-listed it as a candidate key because it is constant.
vintage_tagstringVintage label. CONSTANT literal string 'none' for every row — carries no information.
drug_source_version_idstringIntended drug-source version linkage. 100% NULL — unused/unpopulated in this table. Do not rely on it.
recall_initiation_datedateDate the firm started the recall. The canonical recall start; equals effective_period_start exactly. First in the FDA date chain (init <= center_classification <= report <= termination). Never null; range 2006-02-24 to 2026-05-12.
center_classification_datedateDate the FDA center assigned the hazard classification. Never null. Falls between recall_initiation_date and report_date in 17,151/17,679 rows.
report_datedateDate FDA published the recall in the enforcement report. Never null; range 2012-06-20 to 2026-05-27. This is the best 'when did it become public' date and the most useful for recency/feed-style queries (note it starts in 2012 even though initiation dates go back to 2006).
termination_datedateDate FDA terminated (closed) the recall. NULL for 2,883 rows — essentially all 'Ongoing' (2,452) and most 'Completed' (430), plus 1 'Terminated' edge case. Presence ≈ a closed recall. Last in the date chain.
openfda_brand_namestringopenFDA-enriched brand name (e.g. 'VENTOLIN'). SPARSE: only 3,157/17,679 rows (~18%) enriched; rest NULL because FDA could not match the product to an openFDA drug record. Often equals the generic name for generics.
openfda_generic_namestringopenFDA-enriched generic/established name (e.g. 'ALBUTEROL SULFATE'). Same ~18% coverage as brand (3,157 populated).
openfda_manufacturer_namestringopenFDA-enriched labeler/manufacturer name. ~18% coverage (3,157). May differ from recalling_firm (which is often a repackager/distributor).
openfda_product_ndc_firststringIntended first product NDC from openFDA. 100% NULL across the entire table — completely unpopulated. The profiler listed it as part of a candidate key only because an all-NULL column is trivially 'unique'. DO NOT use for NDC joins; get NDCs from product_description text instead.
openfda_application_number_firststringopenFDA FDA application number (NDA/ANDA/BN...), e.g. 'NDA020983', 'ANDA076477'. Populated for 3,098 rows (~18%); NULL elsewhere. Useful key into FDA drug-application data when present.
openfda_routestringopenFDA route of administration (e.g. 'ORAL', 'INTRAVENOUS', 'RESPIRATORY (INHALATION)'). ~18% coverage (3,106).
openfda_dosage_formstringopenFDA dosage form (tablet, injection, etc.). Same ~18% enrichment coverage as the other openfda_* columns.
openfda_pharm_class_epcstringopenFDA Established Pharmacologic Class (EPC), e.g. 'Angiotensin 2 Receptor Blocker [EPC]', 'Corticosteroid [EPC]'. Sparsest enrichment: only 1,092 rows (~6%) — present only when the matched product has an EPC.

Query it

describe_data_source(source_fqn="drug_silver.fact_drug_recall")     # the card, live
query_substrate(sql="SELECT * FROM drug_silver.fact_drug_recall WHERE recall_number = '<value>' LIMIT 100")
ItemValue
Typed tools that read itrecall_spend_window
Identity keyrecall_number
Joinhow_to_join(source_fqn="drug_silver.fact_drug_recall")
Raw doorAthena (read-only via query_substrate): drug_silver.fact_drug_recall

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