Modeling Categories: The _C_NAME Pattern
Purpose: To understand Epic’s denormalized approach to categorical data in the EHI export.
The Missing Lookup Tables
Section titled “The Missing Lookup Tables”In a traditional database, you’d expect to find lookup tables—small tables mapping codes to descriptions. You might see appointment_status
with rows like (1, 'Scheduled')
, (2, 'Completed')
, (3, 'Canceled')
. But search Epic’s EHI export and you’ll find something surprising:
Instead, Epic uses the _C_NAME
pattern—storing human-readable category names directly in each table.
The Scale of Denormalization
Section titled “The Scale of Denormalization”With 1,695 category columns across the database, this pattern is fundamental to Epic’s data model.
How Categories Work
Section titled “How Categories Work”Let’s examine a typical category column:
Notice the documentation reveals the hidden numeric codes: “1 - Scheduled, 2 - Completed, 3 - Canceled”. These codes exist in Chronicles but are translated to text for the export.
The Hidden Code System
Section titled “The Hidden Code System”Epic’s documentation often exposes the underlying numeric categories:
This proves that Chronicles uses numeric categories internally, but the EHI export provides only the human-readable names.
Why This Matters for Queries
Section titled “Why This Matters for Queries”The denormalized approach has significant implications:
1. Text Matching Instead of Codes
-- You must use text values, not numeric codesSELECT * FROM pat_encWHERE APPT_STATUS_C_NAME = 'Completed'; -- ✓ Correct
SELECT * FROM pat_encWHERE APPT_STATUS_C_NAME = '2'; -- ✗ Won't work
2. Case and Whitespace Sensitivity
3. No Referential Integrity Without lookup tables, there’s no database-enforced consistency:
Common Category Types
Section titled “Common Category Types”Categories follow predictable patterns based on their suffix:
The _C Without _NAME Mystery
Section titled “The _C Without _NAME Mystery”Occasionally you’ll find columns ending in _C
without the _NAME
suffix:
These 66 columns are remnants where the numeric code leaked through, but they’re exceptions to the rule.
Working with Categories
Section titled “Working with Categories”Best practices for the _C_NAME
pattern:
1. Build Category Inventories
2. Handle NULL Values
-- Categories can be NULL - always checkSELECT COUNT(*) as total, COUNT(APPT_STATUS_C_NAME) as with_status, COUNT(*) - COUNT(APPT_STATUS_C_NAME) as missing_statusFROM pat_enc;
3. Use LIKE for Flexible Matching
-- When exact values might varySELECT * FROM diagnosesWHERE DX_CATEGORY_C_NAME LIKE '%Emergency%';
The Trade-offs
Section titled “The Trade-offs”This denormalized approach has pros and cons:
Advantages:
- Human-readable without joins
- Self-contained tables
- Simpler queries for basic reporting
Disadvantages:
- No enforced consistency
- Text matching is less efficient than numeric comparisons
- Category changes require updating all rows
- Potential for typos and variations
Key Takeaways
Section titled “Key Takeaways”- Epic stores category names as text (
_C_NAME
), not numeric codes - 1,695 category columns make this the most common pattern after
LINE
- No
ZC_
lookup tables exist in the EHI export—everything is denormalized - Documentation often reveals the hidden numeric codes from Chronicles
- Always use exact text matching for category values
- This pattern trades referential integrity for simplicity and readability
- Build your own category inventories when consistency matters