HIPAA-Safe Clarity SQL: How to Query Epic Data Without Exposing PHI
HIPAA-safe Clarity SQL means every query returns only the data its purpose requires. You run it from an authorized source, and the output limits re-identification. Most privacy incidents in analytics do not come from attackers. They come from a well-meaning analyst who exports patient-level rows to Excel for a quick check.
I have supported UAT and reporting teams on Epic projects where that export happened. The fix is a set of habits, a few SQL patterns, and a documented access process. This article gives you all three. It is not legal advice. Your privacy officer and counsel decide what your organization may do, and state law can be stricter than HIPAA.
A map of where PHI sits in Clarity, the HIPAA rules that apply to an analyst’s daily work, SQL patterns for aggregation, small-cell suppression, date and ZIP generalization, masked views and row-level security, a decision tree for exports, an access request template, and a downloadable PDF checklist.
Where PHI Lives in Epic Clarity
HIPAA defines protected health information as individually identifiable health information. Data becomes PHI when health information combines with any of 18 identifier types listed in the Privacy Rule. Clarity holds both halves in the same database, often in neighboring tables.
Diagnosis, order, and encounter tables carry health information. Patient and encounter tables carry identifiers. A join between them creates PHI, even when each table looks harmless alone. The table below maps common identifiers to typical Clarity locations.
| HIPAA identifier | Typical Clarity location | Risk note |
|---|---|---|
| Names | PATIENT.PAT_NAME, PATIENT.PAT_FIRST_NAME |
Never needed for count or trend queries. |
| Medical record number | PATIENT.PAT_MRN_ID |
Treated as an identifier even though it is internal. |
| Dates (birth, admission, discharge, service) | PATIENT.BIRTH_DATE, PAT_ENC.CONTACT_DATE, PAT_ENC_HSP.HOSP_ADMSN_TIME |
All elements of a date except year are identifiers under Safe Harbor. |
| Geographic data below state | PATIENT.ADD_LINE_1, CITY, ZIP |
Only the first three ZIP digits may survive, and only for large areas. |
| Phone, email, fax | PATIENT.HOME_PHONE, EMAIL_ADDRESS |
Also appear in free text and contact tables. |
| Social Security number | PATIENT.SSN (restricted at many sites) |
Access is commonly locked down. Do not request it. |
| Account and encounter numbers | PAT_ENC_CSN_ID, HSP_ACCOUNT_ID |
Linkable to a person by anyone with source access. |
| Ages over 89 | Computed from BIRTH_DATE |
Must roll up into one category, such as 90 or older. |
| Any unique code or characteristic | Rare diagnosis plus small department | Small cells can identify a person without any listed identifier. |
Names above follow standard Clarity but vary by version and security configuration. Many organizations restrict or remove some columns from analyst views. Check the Clarity Data Dictionary and your site’s access roles. Assume anything dated, geographic, or numeric about a person is an identifier until you prove otherwise.
A CSN is an identifier, even though it is not on the list by name
Analysts often assume an encounter ID is harmless because it looks like a random number. It is not. Anyone with Epic access can look up the patient from a CSN in seconds. Treat it as an account-number-type identifier, and strip it from anything that leaves the secured environment. The PAT_ENC table guide shows why the CSN is also the join key. That makes it easy to carry into an export by accident.
HIPAA Rules That Shape an Analyst’s Queries
Three parts of HIPAA govern most analytics work: the Privacy Rule, the Security Rule, and the Breach Notification Rule. Each affects the SQL you write, the places you store results, and what you do when something goes wrong.
| Rule | Citation | What it means for a Clarity query |
|---|---|---|
| Minimum necessary | 45 CFR 164.502(b), 164.514(d) | Request and use only the data the task needs. Applies to operations and analytics, not to treatment. |
| De-identification | 45 CFR 164.514(a) to (c) | Data meeting Safe Harbor or Expert Determination is no longer PHI. |
| Limited data set | 45 CFR 164.514(e) | Removes direct identifiers but keeps dates and some geography. Requires a data use agreement. |
| Access control | 45 CFR 164.312(a) | Unique user IDs, role-based access, and automatic logoff apply to database tools. |
| Audit controls | 45 CFR 164.312(b) | Systems must record and examine activity. Your queries may be logged. |
| Workforce training | 45 CFR 164.530(b) | You must be trained on policies before you touch PHI. |
| Breach notification | 45 CFR 164.400 to 414 | Impermissible disclosure triggers a risk assessment and possibly notification. |
The HHS minimum necessary guidance states that covered entities must make reasonable efforts to limit PHI to the minimum necessary. The standard does not apply to disclosures for treatment, which is why a clinician can see a full chart while an analyst cannot.
Three paths to using patient data in analytics
You have three legitimate ways to work with patient-derived data. Each trades detail for protection, and each has a different approval path.
| Path | What you remove | What you keep | Approval needed |
|---|---|---|---|
| Use as PHI for operations | Nothing | Everything, within minimum necessary | Role-based access and a documented purpose |
| Limited data set | Names, street address, phone, MRN, and other direct identifiers | Dates, city, state, ZIP | Data use agreement with the recipient |
| De-identified (Safe Harbor) | All 18 identifier types | Year, state, first three ZIP digits where allowed | None under HIPAA once truly de-identified |
| De-identified (Expert Determination) | Whatever the expert specifies | More detail than Safe Harbor | Qualified statistician’s written determination |
The HHS de-identification guidance explains both methods and the 18 identifiers. Safe Harbor also requires that you have no actual knowledge that the remaining data could identify a person. Rare diagnoses in small facilities can fail that test.
Scenario: A UAT Evidence File with 2,000 MRNs Sent by Email
A regional health system was testing a new referral workflow before go-live. A QA analyst needed to prove that referral orders reached the right departments. She joined patients, encounters, and orders in Clarity and exported 2,000 rows to Excel. Then she emailed the file to a vendor consultant as test evidence.
The file held MRNs, birth dates, encounter dates, and diagnosis names. The vendor consultant’s email address was correct, but the vendor contract did not cover PHI from the production environment. The privacy office learned of it two days later during a routine mail review.
The privacy officer documented a risk assessment and decided on next steps. That decision belongs to compliance, and analysts should not guess at the outcome. What I could control was the test process. The team rewrote the evidence rule and built a masked reporting view.
The before query
-- BEFORE: row-level PHI exported as test evidence
SELECT p.PAT_MRN_ID, p.PAT_NAME, p.BIRTH_DATE,
e.PAT_ENC_CSN_ID, e.CONTACT_DATE,
o.ORDER_PROC_ID, o.DESCRIPTION,
dx.DX_NAME
FROM PATIENT p
JOIN PAT_ENC e ON e.PAT_ID = p.PAT_ID
JOIN ORDER_PROC o ON o.PAT_ENC_CSN_ID = e.PAT_ENC_CSN_ID
JOIN PAT_ENC_DX x ON x.PAT_ENC_CSN_ID = e.PAT_ENC_CSN_ID
JOIN CLARITY_EDG dx ON dx.DX_ID = x.DX_ID
WHERE o.DESCRIPTION LIKE '%REFERRAL%'
AND e.CONTACT_DATE >= '2026-09-01';
The after query
-- AFTER: aggregate evidence, no identifiers, small cells suppressed
SELECT d.DEPARTMENT_NAME AS referral_department,
DATEFROMPARTS(YEAR(e.CONTACT_DATE), MONTH(e.CONTACT_DATE), 1) AS month_start,
COUNT(DISTINCT o.ORDER_PROC_ID) AS referral_orders
FROM ORDER_PROC o
JOIN PAT_ENC e ON e.PAT_ENC_CSN_ID = o.PAT_ENC_CSN_ID
JOIN CLARITY_DEP d ON d.DEPARTMENT_ID = o.REFERRAL_DEPT_ID -- placeholder column name
WHERE o.DESCRIPTION LIKE '%REFERRAL%'
AND e.CONTACT_DATE >= '2026-09-01'
GROUP BY d.DEPARTMENT_NAME,
DATEFROMPARTS(YEAR(e.CONTACT_DATE), MONTH(e.CONTACT_DATE), 1)
HAVING COUNT(DISTINCT o.ORDER_PROC_ID) >= 11;
The aggregate answers the test question. Did referral orders reach the expected departments in the expected numbers? The vendor needed no names, no dates, and no MRNs. The REFERRAL_DEPT_ID column is a placeholder for whichever field your build uses to store the receiving department.
For the few cases where a tester must trace one order, use a test patient created for UAT, and cite the test MRN. Real patients do not belong in non-production evidence.
The organization, ticket number, and counts are a composite drawn from several privacy reviews. The failure pattern is common: an evidence requirement that does not say what format is acceptable.
SQL Patterns That Reduce PHI Exposure
Six patterns cover most analytics requests. Use them in order: aggregate first, generalize second, mask third, restrict fourth.
Pattern 1: Aggregate instead of listing
Most business questions need counts, rates, or averages, not rows. Rewrite the request before you write the query. Ask what decision the number supports, and the aggregate usually answers it.
| Request as received | Rewritten request | Query shape |
|---|---|---|
| “List patients with a missed follow-up” | “How many patients missed a follow-up, by clinic and month?” | COUNT(DISTINCT PAT_ID) with GROUP BY |
| “Show me the readmissions” | “What is the 30-day readmission rate by unit?” | Numerator and denominator counts |
| “Send the test patients’ results” | “Did the interface deliver 50 of 50 test messages?” | Count with pass/fail flag |
Pattern 2: Suppress small cells
A count of one or two can identify a person, especially for a rare condition in a small clinic. CMS suppresses cells with fewer than eleven beneficiaries in its public data products. Many health systems adopt the same threshold for internal reports shared outside the care team. Check your own policy for the number.
SELECT d.DEPARTMENT_NAME, dxg.DX_GROUP_NAME,
COUNT(DISTINCT e.PAT_ID) AS patients
FROM PAT_ENC e
JOIN CLARITY_DEP d ON d.DEPARTMENT_ID = e.DEPARTMENT_ID
JOIN RPT_DX_GROUP_MAP dxg ON dxg.PAT_ENC_CSN_ID = e.PAT_ENC_CSN_ID -- your governed mapping table
WHERE e.CONTACT_DATE >= '2026-01-01' AND e.CONTACT_DATE < '2026-10-01'
GROUP BY d.DEPARTMENT_NAME, dxg.DX_GROUP_NAME
HAVING COUNT(DISTINCT e.PAT_ID) >= 11;
Suppression has a weakness called differencing. If a report shows the total and all but one cell, the missing cell is easy to compute. Suppress a second cell, or publish only the totals, when both a cell and its complement are exposed.
Pattern 3: Generalize dates, ages, and ZIP codes
SELECT CASE WHEN age_years >= 90 THEN '90+'
WHEN age_years >= 65 THEN '65-89'
WHEN age_years >= 40 THEN '40-64'
WHEN age_years >= 18 THEN '18-39'
ELSE '0-17' END AS age_band,
YEAR(x.CONTACT_DATE) AS contact_year,
CASE WHEN z.ZIP3 IS NULL THEN '000' ELSE z.ZIP3 END AS zip3,
COUNT(*) AS encounters
FROM (SELECT e.CONTACT_DATE, e.PAT_ID,
DATEDIFF(year, p.BIRTH_DATE, e.CONTACT_DATE)
- CASE WHEN DATEADD(year, DATEDIFF(year, p.BIRTH_DATE, e.CONTACT_DATE), p.BIRTH_DATE) > e.CONTACT_DATE
THEN 1 ELSE 0 END AS age_years,
LEFT(p.ZIP, 3) AS zip3_raw
FROM PAT_ENC e JOIN PATIENT p ON p.PAT_ID = e.PAT_ID
WHERE e.CONTACT_DATE >= '2026-01-01' AND e.CONTACT_DATE < '2026-10-01') x
LEFT JOIN RPT_ZIP3_ALLOWED z ON z.ZIP3 = x.zip3_raw -- ZIP3 areas above 20,000 people
GROUP BY CASE WHEN age_years >= 90 THEN '90+' WHEN age_years >= 65 THEN '65-89'
WHEN age_years >= 40 THEN '40-64' WHEN age_years >= 18 THEN '18-39' ELSE '0-17' END,
YEAR(x.CONTACT_DATE),
CASE WHEN z.ZIP3 IS NULL THEN '000' ELSE z.ZIP3 END;
Safe Harbor lets you keep the first three ZIP digits only when all ZIP codes sharing those digits cover more than 20,000 people. Otherwise replace them with 000. The Census Bureau publishes the population data you need to build the allowed list. Notice also that the age calculation corrects for birthdays not yet reached, which plain DATEDIFF(year) gets wrong. Generalizing dates also breaks metrics that need exact timestamps, such as a Clarity LOS calculation. Decide which reports need full dates under a limited data set.
Pattern 4: Never hash an identifier and call it de-identified
Analysts often replace the MRN with a hash and consider the data safe. It is not de-identified. The Privacy Rule says a re-identification code must not be derived from information about the individual. A hash of an MRN is derived from it, and anyone with the MRN list can recompute the hash.
| Technique | What it gives you | Does it meet Safe Harbor? |
|---|---|---|
| Hash of MRN (SHA-256) | Consistent pseudonym, reversible by lookup | No. Derived from the identifier. |
| Salted hash, salt kept secret | Harder to reverse without the salt | No for Safe Harbor. May support a limited data set with controls. |
| Random surrogate key from a lookup table | Consistent pseudonym with no mathematical link | Yes, if the lookup table stays inside the secured environment. |
| Drop the identifier | No linkage across extracts | Yes, for this identifier. |
-- Random surrogate key, assigned once and stored securely
INSERT INTO rpt_secure.PAT_SURROGATE (PAT_ID, SURROGATE_KEY)
SELECT p.PAT_ID, NEWID()
FROM PATIENT p
WHERE NOT EXISTS (SELECT 1 FROM rpt_secure.PAT_SURROGATE s WHERE s.PAT_ID = p.PAT_ID);
Restrict the lookup table to the few people who maintain it. Anyone who can read both the surrogate table and the source can reverse the mapping.
Where Results Go: Tool Risk Comparison
A safe query still becomes unsafe when the output lands in the wrong place. Each tool you use to view or share results carries a different exposure profile. The table below ranks the tools I see most often on Epic projects.
| Destination | Risk with row-level PHI | Why | Safer use |
|---|---|---|---|
| SQL client on the secured server | Low | Data stays inside controlled access and logging | Preferred for investigation |
| Reporting Workbench inside Epic | Low | Epic security classes and audit trail apply | Operational lists for staff with access |
| Governed BI platform with row-level security | Low to medium | Depends on role design and sharing settings | Dashboards on de-identified models |
| Excel on a managed laptop | Medium | Local copies, autosave, cloud sync | Aggregates only, delete on schedule |
| Email attachment | High | Leaves the environment, forwards easily, hard to recall | Never for row-level PHI |
| Jira or ticket attachment | High | Broad visibility, version history keeps old files | Masked screenshots and counts |
| Chat tools and AI assistants | High | Third-party processing without an agreement | No PHI unless the tool is approved |
Most incidents I have reviewed involved the last four rows. The analyst used the tool for convenience and never considered where a copy would persist. Make the safe path the easy path by providing a secured share and a masked view.
How Access to Clarity Usually Works
Clarity access is a local decision, and it varies more than people expect. A typical arrangement gives analysts a database login tied to an Active Directory group. The group maps to a role that can read selected tables or views on a reporting server, never the Chronicles production system.
Some sites grant broad read access to all Clarity tables for a small team of senior analysts. Others expose only curated views. The curated model costs more to maintain and removes most accidental exposure. If your organization offers it, use it.
| Access model | Strength | Weakness |
|---|---|---|
| Broad read on all tables | Fast investigation, no view maintenance | Any query can touch any identifier. Relies on analyst discipline. |
| Curated reporting views | Identifiers removed by design | Slower to add new fields. Needs governance. |
| Role-based views plus row-level security | Scoped to department or facility | Complex to administer. Easy to misconfigure. |
| Request-based elevation with expiry | Identified data only when justified | Adds a ticket step. Needs an owner for approvals. |
Ask your Clarity administrator which model you work under. If the answer is “everything,” your own habits are the only control. Apply the checklist at the end of this article to every query.
If It Goes Wrong: The First Hour
Mistakes happen, and how you respond matters more than the mistake. Analysts who report quickly keep a small problem small. Analysts who hide a mistake create a larger one.
Stop sending the data. Do not forward, delete, or edit anything yet, because the privacy team needs the original facts. Write down what you sent, to whom, when, and through which channel. Then call or message your privacy officer or security contact directly, using the incident process your organization defined.
| Step | Action | What not to do |
|---|---|---|
| 1 | Stop further sharing or access | Do not try to quietly fix it first |
| 2 | Record who, what, when, and where | Do not guess at details you cannot confirm |
| 3 | Report to the privacy office immediately | Do not wait for the end of the sprint |
| 4 | Preserve the evidence as instructed | Do not delete files before the team says so |
| 5 | Support the risk assessment | Do not decide on your own whether it is a breach |
| 6 | Fix the process after the review | Do not blame the individual in the ticket |
Under the Breach Notification Rule, a covered entity evaluates an impermissible use or disclosure through a documented risk assessment. That assessment considers the nature of the data, the recipient, whether it was actually viewed, and how well the risk has been reduced. Your report starts that clock.
After the review, convert the lesson into a control. The email incident above produced a masked view, a revised evidence standard, and a short training segment. A new rule alone would have been forgotten within a quarter.
Masked Evidence for Jira and Test Reports
QA teams attach screenshots to tickets all day, and each screenshot can carry an MRN, a name, or a date of birth. Build masking into the test routine rather than rely on memory at the end of a long day.
Use test patients wherever the environment allows it. Crop to the relevant field. Replace visible identifiers with a solid box rather than a blur, because blur can sometimes be reversed. Check the ticket after upload, including the attachment preview, and confirm the filename does not contain a patient name.
A ticket like this gives developers what they need without carrying real patient data into a tool with broad visibility. Note the explicit data-handling line. It reminds reviewers to check, and it gives auditors a clear record.
Pattern 5: Give analysts a masked view, not the base tables
Habits fail under deadline pressure. Structure holds. Build a reporting schema with views that already exclude names, street addresses, and exact birth dates, and grant analysts access to the views only.
CREATE VIEW rpt_safe.vw_encounter_deid AS
SELECT s.SURROGATE_KEY AS person_key,
YEAR(e.CONTACT_DATE) AS contact_year,
MONTH(e.CONTACT_DATE) AS contact_month,
e.DEPARTMENT_ID,
e.ENC_TYPE_C,
e.APPT_STATUS_C
FROM PAT_ENC e
JOIN rpt_secure.PAT_SURROGATE s ON s.PAT_ID = e.PAT_ID;
GO
GRANT SELECT ON SCHEMA::rpt_safe TO analyst_role;
DENY SELECT ON PATIENT TO analyst_role;
A view limits what the query can return, but it does not by itself prove that the data is de-identified. Dates by month and department may still identify someone in a small clinic. Have your privacy officer approve the view design, and document the approval.
Pattern 6: Restrict rows with row-level security
Some analysts should see only one hospital or one service line. SQL Server row-level security applies a predicate to every query, so the restriction does not depend on each author remembering a WHERE clause.
CREATE FUNCTION rpt_safe.fn_dept_filter(@DEPARTMENT_ID NUMERIC(18,0))
RETURNS TABLE WITH SCHEMABINDING AS
RETURN SELECT 1 AS allowed
FROM rpt_secure.ANALYST_DEPT_ACCESS a
WHERE a.LOGIN_NAME = USER_NAME() AND a.DEPARTMENT_ID = @DEPARTMENT_ID;
GO
CREATE SECURITY POLICY rpt_safe.DeptPolicy
ADD FILTER PREDICATE rpt_safe.fn_dept_filter(DEPARTMENT_ID) ON rpt_safe.encounter_table
WITH (STATE = ON);
Apply this on a reporting copy or a warehouse table, not on Epic’s own Clarity tables. Epic controls those, and local changes can break upgrades. Oracle offers Virtual Private Database for the same purpose, and Snowflake has row access policies.
Decision Tree: Can You Run and Export This Query?
Run every request through this tree before you hit execute. The first two questions stop most incidents.
Do I have a documented purpose
and role-based access?
No: stop,
request access
Yes
Can an aggregate answer it?
Counts, rates, averages
Yes
No
Aggregate it
Suppress cells under the
policy threshold. Check for
differencing. Export is low risk.
Do you need row-level data?
Use the de-identified view.
Drop MRN, CSN, name, full
dates, address.
Is identifiable detail truly
required?
Ask the privacy officer first.
Row-level PHI stays inside
the secured environment
No email, no personal laptop,
no unsecured Excel or chat.
Share via approved tools only.
The tree ends in the same place for most requests: the data stays inside. Moving it out requires a business associate agreement, a data use agreement, or a documented de-identification, and those take time to arrange.
Scenario: A Vendor Asks for a Readmission Extract
A health system hired an analytics vendor to model readmission risk. The vendor asked for three years of encounters with dates, diagnoses, and ZIP codes. The project manager asked me whether the team could “just pull it.”
The answer depended on the contract and the data. With a business associate agreement in place, the health system may disclose PHI to the vendor for the covered purpose, still under minimum necessary. Without one, it cannot. Even with the agreement, the vendor did not need names, street addresses, or phone numbers.
We agreed on a limited data set. The extract kept admission and discharge dates, city, state, and ZIP, because readmission modeling needs time between encounters. It dropped names, street addresses, phone numbers, MRNs, and account numbers, and replaced the MRN with a random surrogate key. A data use agreement covered the rest.
| Element | Original extract request | Limited data set delivered |
|---|---|---|
| Patient identifier | MRN | Random surrogate key |
| Name, street address, phone | Included | Removed |
| Admission and discharge dates | Included | Included (permitted in a limited data set) |
| ZIP code | Five digits | Five digits (permitted) |
| Birth date | Full date | Full date (permitted) |
| Diagnosis codes | ICD-10 codes | ICD-10 codes |
| Legal basis | Not stated | Business associate agreement plus data use agreement |
Keeping dates mattered for the model. A Safe Harbor version would have reduced everything to year and killed the readmission interval. That is the tradeoff: more utility needs more controls. A different project might have chosen Expert Determination to keep some detail without a data use agreement.
Counsel reviewed the agreements. My role was to build the extract, test that the removed fields were absent, and document the field list that the privacy officer approved.
Template: Data Access Request for Analysts
Copy this into your ticketing system. A complete request takes five minutes to write and removes most of the back-and-forth with privacy and security teams.
| Field | What to write | Example |
|---|---|---|
| Requester and role | Name, team, manager | QA analyst, Referral Workflow project |
| Purpose | The decision or task the data supports | Verify referral orders reach the right departments before go-live |
| Legal basis | Operations, quality improvement, research, or other | Health care operations |
| Data needed | Fields, date range, population | Order counts by department and month, Sept 2026 |
| Identifiers needed | None, or list each with a reason | None |
| Granularity | Aggregate or row-level, and why | Aggregate with cells under 11 suppressed |
| Environment | Where the query runs and where results live | Clarity reporting server; results stay in the secured share |
| Sharing | Who receives the output | Project team only. No external recipients. |
| Retention | When the output is deleted | 30 days after sign-off |
| Approver | Privacy officer or data steward | Name and date |
Audit Trails: Assume Every Query Leaves a Record
The Security Rule requires audit controls. In practice, your database platform, your reporting tools, and Epic’s own access logs may all record who ran what and when. Privacy teams review those logs after incidents and, at many organizations, during routine monitoring.
Write queries you would defend. Name the ticket in a comment at the top. Avoid exploratory SELECT * against patient tables, because the log shows that you touched every column. Keep a short record of why you ran each production query. When someone asks in six months, you will have an answer.
/* Ticket: SEC-0932-followup | Purpose: referral order counts for UAT sign-off
Requester: QA | Approved by: Privacy Office 2026-10-02 | Aggregate only */
SELECT d.DEPARTMENT_NAME, COUNT(DISTINCT o.ORDER_PROC_ID) AS referral_orders
FROM ORDER_PROC o
JOIN CLARITY_DEP d ON d.DEPARTMENT_ID = o.REFERRAL_DEPT_ID
GROUP BY d.DEPARTMENT_NAME
HAVING COUNT(DISTINCT o.ORDER_PROC_ID) >= 11;
Do not look up patients you know personally, and never browse a coworker’s record out of curiosity. Snooping is a leading source of access violations in health systems, and audit logs catch it.
Role Checklists for HIPAA-Safe Clarity Work
Business Analyst
- Specify the data format in the requirement: aggregate, de-identified, or identified, and who approves.
- Write “no PHI in test evidence” into the test plan.
- Add the data access request to the project intake, not to the week before go-live.
- Identify business associate and data use agreements before a vendor requests data.
QA Analyst
- Use test patients in non-production. Record their MRNs in the test plan.
- Capture screenshots with identifiers masked or cropped.
- Check exported files for hidden columns, extra sheets, and cell comments.
- Delete evidence on the retention schedule and log the deletion.
Data Analyst
- Work from de-identified views by default. Request elevation with a purpose.
- Apply small-cell suppression and check for differencing.
- Keep surrogate key tables in a restricted schema.
- Comment every production query with a ticket and purpose.
Common HIPAA Mistakes in Clarity Work
| Mistake | Why it fails | Fix |
|---|---|---|
| Exporting row-level data for a quick check | Local copies escape retention and access controls | Run the check in SQL and export counts |
| Hashing the MRN and calling it de-identified | The code is derived from the identifier | Use random surrogate keys or drop the field |
| Pasting query results into chat tools or AI assistants | Disclosure to a third party without an agreement | Use approved tools only, with no PHI in prompts |
| Leaving dates and ZIP codes in “anonymous” extracts | Both are identifiers under Safe Harbor | Generalize to year and ZIP3 where allowed |
| Assuming test environments are safe | Production copies hold real PHI | Confirm the environment is scrubbed before you use it |
| Sharing a screenshot with a visible MRN | The identifier travels with the image | Crop or mask before attaching to Jira |
| Ignoring small cells | Counts of one or two identify people | Suppress below the policy threshold |
I once pasted a failing query result into a support ticket for the vendor, with the patient columns blanked out in the sheet. The ticket system kept the original attachment version. Always check what a tool stores, not only what it shows.
When I Would Use Each Protection
For recurring dashboards, I build de-identified views once and point all reports at them. It costs a week of setup and saves a monthly debate. For one-time validation, I aggregate and suppress. For vendor work, I start with the contract and then pick the lightest data path that supports the model.
I use full identified access only for tasks that cannot work otherwise, such as a patient-level reconciliation for a billing dispute. Those run on the secured server, under a ticket, with results stored in an approved location and deleted on schedule.
For enterprise reporting, a governed model in Caboodle with built-in masking beats ad hoc Clarity queries. Validate it with the aggregate patterns above. The Epic Clarity SQL guide and the SQL for IT Analysts hub show where to find the query patterns that support those checks.
Edge Cases That Break Clean Privacy Rules
| Edge case | Why it matters | How to handle it |
|---|---|---|
| Substance use disorder records | 42 CFR Part 2 adds consent requirements beyond HIPAA for covered programs | Ask compliance which records carry Part 2 flags before you pull diagnosis data. |
| Mental health and psychotherapy notes | Special protections apply under HIPAA | Exclude note text from analytics unless approved. |
| State laws stricter than HIPAA | Examples include state rules on HIV, minors, and reproductive health data | HIPAA sets a floor. Confirm local requirements with counsel. |
| Minors and adolescents | Confidential services may not be visible to parents or guardians | Check proxy and confidentiality flags before building patient-facing reports. |
| VIP and employee patients | Higher snooping risk and tighter access rules | Respect restrictions. Exclusions may exist in your data. |
| Small populations | A rare diagnosis in a rural clinic identifies a person without any direct identifier | Suppress or aggregate to a higher level. |
| Free-text fields | Notes can contain names, numbers, and addresses | Exclude free text unless a scrubbing process is approved. |
Legal requirements change. Confirm anything that carries regulatory weight with your privacy officer or counsel before you build on it. This article describes common practice, not a ruling on your situation.
A Pre-Run Checklist for Any Clarity Query
| Check | Question | Pass condition |
|---|---|---|
| 1. Purpose | Can I state the decision this query supports? | One sentence, written in the ticket |
| 2. Access | Do I have approved, role-based access? | Access request on file |
| 3. Minimum | Does the SELECT list contain only needed columns? | No names, MRN, CSN, or full dates unless justified |
| 4. Aggregate | Can counts answer this? | Aggregate unless a reason is documented |
| 5. Small cells | Are cells under the threshold suppressed? | HAVING clause or post-filter applied |
| 6. Destination | Where will results live? | Secured share, never email or personal device |
| 7. Retention | When will I delete them? | Date in the ticket |
Questions Analysts Ask About HIPAA and Clarity
Is Clarity data always PHI?
Not every table, but any query that combines health information with an identifier produces PHI. Treat Clarity as PHI by default.
Can I use real patient data in a test environment?
Only if your organization has authorized it and applied the same safeguards as production. Many sites scrub non-production copies. Confirm yours is scrubbed before you rely on it.
Does removing the patient name make a dataset de-identified?
No. De-identification requires removing or generalizing all 18 identifier types, or a qualified expert’s determination. Dates, ZIP codes, and record numbers still identify people.
Is it safe to paste query results into an AI assistant?
Not unless your organization has approved that tool and signed the required agreements. Treat pasted PHI as a disclosure.
Who decides whether an incident is a breach?
Your privacy officer, using the risk assessment that the Breach Notification Rule requires. Report the incident quickly and let them decide.
Run This Before Your Next Export
Open the last query you exported and read its SELECT list. Count the identifiers: names, MRNs, CSNs, full dates, addresses. For each one, write the reason you needed it. If you cannot write a reason, rewrite the query as an aggregate. That ten-minute audit of your own work prevents the next SEC ticket.
Sources and Further Reading
- HHS: Guidance Regarding Methods for De-identification of PHI. Defines Safe Harbor, the 18 identifiers, and Expert Determination.
- HHS: Minimum Necessary Requirement. Official guidance on limiting PHI use and disclosure.
- 45 CFR Parts 160 and 164 (HIPAA Administrative Simplification regulations) on eCFR. Citations in this article refer to these parts.
- Epic Clarity Data Dictionary on Epic UserWeb (requires an Epic customer login). Authority for column names in your version.
This article does not constitute legal advice. Table and column names follow standard Clarity and vary by site. Placeholder objects are marked in the code.
