SQL Query to Power BI Report

A Business Analyst Workflow From Requirement to Dashboard

Turning a SQL query into a Power BI report fails most often before anyone opens Power BI. The metric is undefined, the query returns the wrong grain, or the audience sees data they should not. This article gives a business analyst workflow from requirement to published dashboard, with the SQL, the DAX, the tests, and the tickets I use.

I have built and tested reports on Epic Clarity, revenue cycle, and finance data. I have also reviewed reports that looked polished and carried wrong numbers. The steps below separate what belongs in SQL, in the model, and in the visuals, so a defect has one obvious home.

What you will take away
A twelve-step workflow. A report specification template. The SQL view, Power Query, and DAX for a working example. Import and DirectQuery guidance. Two scenarios with tickets and before/after code, a UAT checklist, role cards, and a PDF you can print.

SQL Query to Power BI Report: The Workflow in One Table

Think of the path as a chain of handoffs. Each link has an owner, an output, and a check. A report is correct only when every link is correct.

Step What happens Owner Output Check
1 Define the question and the decision Business analyst Problem statement Business owner confirms
2 Write the metric definitions Business analyst Metric sheet Signed definition
3 Specify the report Business analyst Report spec Stakeholder review
4 Profile the source data in SQL Business analyst or data analyst Profile queries Fields populated as expected
5 Build a governed SQL view Data analyst or developer View at a stated grain Grain and count tests
6 Connect Power BI and choose a storage mode Report developer Connected semantic model Mode decision recorded
7 Model the data Report developer Star schema, date table, relationships Relationship tests
8 Write DAX measures Report developer Measures Match SQL totals
9 Design the visuals Report developer and BA Report pages Usability review
10 Secure the data Report developer and security Row-level security, workspace roles View-as tests
11 Publish, schedule refresh Report developer Service report, gateway, refresh Refresh succeeds
12 Test, sign off, monitor QA and business analyst UAT record Reconciled and approved

Notice how many steps happen before the connection in step 6. Analysts who open Power BI first spend the project fixing, in DAX, problems that a better query would have prevented.

RequirementMetric + spec
SQL viewGrain + filters
Semantic modelStar schema
DAX + visualsMeasures, pages
Published reportSecurity + refresh
Owner: BA
Owner: data analyst
Owner: report developer
Owner: security + dev
QA reconciles every stage to the one before it: SQL to source, report to SQL
Defects have one home. A wrong grain is a SQL defect. A wrong ratio is a DAX defect. A wrong audience is a security defect.

Steps 1 to 3: Requirement, Metric Definition, and Report Spec

Power BI is a delivery tool. The business analyst’s main contribution happens in three documents that exist before the first query. They answer who decides what, using which numbers.

Metric sheet

Write one row per metric. The numerator, denominator, exclusions, grain, and owner prevent the disputes that follow a published dashboard. The which tool to master first article and the earlier role comparison use the same template.

Field Example
Metric Average length of stay (LOS)
Decision supported Unit managers adjust staffing for discharge flow
Definition Midnights between admit and discharge, averaged over discharges in the period
Grain One row per inpatient discharge
Exclusions Observation stays, newborns, and encounters with no discharge time
Owner and version Director of operations; v1, effective Oct 1

Report specification

Item What to write
Audience and access Unit managers see their units; directors see all units; no patient-level detail
Questions per page Page 1: How many discharges and what is average LOS? Page 2: Which units changed most?
Filters and slicers Month, unit, service line; default is the last complete month
Visuals Cards for discharges and LOS, trend line by month, ranked bar by unit, table of units
Refresh Daily at 7:00, after the nightly Clarity load completes
Performance target Pages load in under five seconds with default filters
Out of scope Readmissions, financial measures, patient lists

Get the stakeholder to sign the spec. A signed “out of scope” list does more to protect a schedule than any estimate.

Steps 4 and 5: From SQL Query to Power BI Report Starts With a Governed View

Profile the source before you write the final query. The profile tells you which fields are populated, what values exist, and what the grain is. It also shows data gaps while a fix is still cheap.

Profile first, then build
-- Profile 1: row count, date range, and nulls in the fields the report needs
SELECT  COUNT(*)                                              AS encounters,
        MIN(HOSP_DISCH_TIME)                                  AS first_discharge,
        MAX(HOSP_DISCH_TIME)                                  AS last_discharge,
        SUM(CASE WHEN HOSP_DISCH_TIME IS NULL THEN 1 ELSE 0 END)  AS no_discharge_time,
        SUM(CASE WHEN DEPARTMENT_ID  IS NULL THEN 1 ELSE 0 END)   AS no_department
FROM    PAT_ENC_HSP
WHERE   HOSP_ADMSN_TIME >= '2025-01-01';

-- Profile 2: is the intended key unique?
SELECT  PAT_ENC_CSN_ID, COUNT(*) AS copies
FROM    PAT_ENC_HSP
GROUP BY PAT_ENC_CSN_ID
HAVING  COUNT(*) > 1;

Then build the view. A view gives you one named, reviewable, testable object. Power BI reads it, and so does anyone who needs to check the numbers. The Epic Clarity SQL guide covers the tables behind the example.

A fact view and a dimension view
CREATE VIEW rpt.vw_discharge AS
SELECT  h.PAT_ENC_CSN_ID                                    AS encounter_csn,
        CAST(h.HOSP_DISCH_TIME AS date)                     AS discharge_date,
        h.DEPARTMENT_ID                                     AS department_id,
        DATEDIFF(day, h.HOSP_ADMSN_TIME, h.HOSP_DISCH_TIME) AS los_days
FROM    PAT_ENC_HSP h
WHERE   h.HOSP_DISCH_TIME IS NOT NULL
  AND   h.ADT_PAT_CLASS_C = 1;          -- inpatient; confirm the code in your data dictionary

CREATE VIEW rpt.vw_department AS
SELECT  d.DEPARTMENT_ID AS department_id, d.DEPARTMENT_NAME AS department_name, m.service_line
FROM    CLARITY_DEP d
LEFT JOIN ref.unit_service_line m ON m.department_id = d.DEPARTMENT_ID;

Notice what the view leaves out. No patient identifier, no name, no date of birth. The report asks about volume and length of stay, so minimum necessary says the model needs none of them. If a stakeholder later asks for patient lists, treat it as a new requirement with its own approval.

Tests for the view before Power BI sees it

Grain, count, and orphan checks
-- Grain: one row per encounter
SELECT encounter_csn, COUNT(*) FROM rpt.vw_discharge GROUP BY encounter_csn HAVING COUNT(*) > 1;   -- expect 0 rows

-- Completeness: view count equals an independent source count
SELECT (SELECT COUNT(*) FROM rpt.vw_discharge WHERE discharge_date >= '2026-09-01' AND discharge_date < '2026-10-01') AS view_rows,
       (SELECT COUNT(*) FROM PAT_ENC_HSP WHERE HOSP_DISCH_TIME >= '2026-09-01' AND HOSP_DISCH_TIME < '2026-10-01'
                                          AND ADT_PAT_CLASS_C = 1) AS source_rows;

-- Orphans: every department in the fact exists in the dimension
SELECT DISTINCT f.department_id FROM rpt.vw_discharge f
LEFT JOIN rpt.vw_department d ON d.department_id = f.department_id WHERE d.department_id IS NULL;   -- expect 0 rows

These are the same families the ETL validation SQL article uses for warehouse loads. A report view is a small load, and it deserves the same tests.

Step 6: Connect Power BI and Choose Import or DirectQuery

Power BI Desktop connects to SQL Server and many other sources. Connect to the view, not to a pasted query. A pasted query hides logic inside the report file and can stop Power BI from pushing later transformations back to the database.

Power Query (M): connect to the view
let
    Source    = Sql.Database("sqlserver01", "Reporting"),
    Discharge = Source{[Schema = "rpt", Item = "vw_discharge"]}[Data]
in
    Discharge

Then choose how Power BI stores the data. The decision affects speed, freshness, and which features work. Record it in the spec.

Factor Import DirectQuery
Where data lives for reports Copied into the semantic model and refreshed on schedule Left in the source; each visual sends queries when viewed
Freshness As fresh as the last refresh Close to live, depending on source load
Report speed Usually fast; data sits in memory Depends on source and query design
Load on the source At refresh time only On every interaction
Feature coverage Full Power Query and DAX Some transformations and functions limited
Size limits Capped by license and capacity; check your tier Source holds the data
Best for Most departmental dashboards Very large or near-real-time needs with a tuned source

Import fits most hospital and finance dashboards because yesterday’s data is enough and users expect speed. Choose DirectQuery only when freshness or size forces it, and tune the source first. The Microsoft Power BI documentation explains composite models, which mix both modes in one model.

Steps 7 and 8: Model the Data and Write DAX Measures

Shape the model as a star: one fact table in the middle, dimension tables around it. Relationships run from each dimension to the fact table, one to many, with a single filter direction.

Modeling rule Why
One fact table at a stated grain Every measure counts the same thing
Separate dimension tables for department, date, and service line Filters work the same on every page
A complete date table marked as the date table Time intelligence functions need contiguous dates
One-to-many relationships, single direction Avoids ambiguous filters and double counting
Hide keys and technical columns Report authors see only what is safe to use
Measures, not calculated columns, for ratios Measures respond to the filters in each visual
Measures built from sums and counts
Discharges      = COUNTROWS ( fact_discharge )
Total LOS Days  = SUM ( fact_discharge[los_days] )
Avg LOS         = DIVIDE ( [Total LOS Days], [Discharges] )

Discharges PM   = CALCULATE ( [Discharges], DATEADD ( dim_date[Date], -1, MONTH ) )
Discharges MoM% = DIVIDE ( [Discharges] - [Discharges PM], [Discharges PM] )

Build ratios from totals, as Avg LOS does. Never average an averaged column. Scenario one below shows how that mistake produces a believable and wrong number. The DAX reference lists each function. The window functions article covers the SQL equivalents of period comparison.

Logic Put it in SQL Put it in Power Query Put it in DAX
Joins, filters, row-level business rules Yes Only if the source cannot No
Column renaming and type fixes Yes, in the view Acceptable for report-only needs No
Ratios and totals that respond to filters No No Yes, as measures
Time comparisons For fixed reports No Yes, with a date table
Sorting and formatting No No Report layer

The rule I follow is simple. Put row-level logic as low as possible and aggregate logic as high as possible. That keeps one definition per rule and makes defects easy to find.

Steps 9 to 12: Visuals, Security, Refresh, and Sign-Off

Step 9: Design pages around questions

Give each page one question and put the answer first. A card for discharges and average LOS, a trend, and a ranked bar usually answer a unit manager. Put the metric definition in a tooltip or a small info panel, so a viewer who doubts a number can read the rule.

Design rule Reason
One question per page Viewers find the answer without searching
Default filter set to the last complete month Partial months look like drops
Show the data refresh time on every page Viewers know how fresh the numbers are
Avoid patient identifiers in tooltips and tables Minimum necessary applies to visuals too
Use colors with enough contrast and add labels Accessibility and printed copies
Limit visuals per page Speed and readability

Step 10: Secure the data

Row-level security limits which rows a viewer sees. You define roles in Power BI Desktop with DAX filters and assign people to them in the service. A common pattern maps each manager’s sign-in to the departments they own.

A dynamic row-level security filter
-- Role: UnitManagers   Table: dim_department   Filter expression:
[manager_email] = USERPRINCIPALNAME ()

Filters flow from dimension to fact through relationships, so this one filter also restricts the discharge rows. Test each role with the “View as” feature before publishing. Then test it again in the service.

Workspace roles can bypass row-level security
Row-level security applies to viewers. People with edit permission in a workspace, such as members and contributors, can see all the data. Give report consumers the viewer role or share through an app, and keep editor roles for the build team. Confirm current behavior in the Microsoft documentation for your tenant.

Step 11: Publish and schedule refresh

Publish from Desktop to a workspace. If the SQL server sits inside your network, the service reaches it through an on-premises data gateway. Use a service account for credentials, not a personal sign-in that expires when someone changes jobs.

Refresh decision Guidance
When to refresh After the source load finishes. A Clarity nightly load may end at an unpredictable hour, so check the job history before you set a time
Who gets alerts Name an owner and a backup; send failures to a monitored address
Credentials Service account with read-only rights to the reporting schema
Incremental data Consider incremental refresh for large fact tables; confirm license support
After a source change Retest the view tests and refresh the model before users see the change

Step 12: Test, reconcile, and sign off

Test Method Pass rule
Totals tie to SQL Compare card values to a direct query for the same filters Exact match
Ratios tie to SQL Compute SUM over COUNT in SQL for two units and one month Matches to the displayed decimals
Filters behave Apply unit, month, and service line filters in combinations Totals respond as expected
Blank and edge periods Select a month with no discharges and the current partial month Blank or labeled, no errors
Security “View as” each role; test one user outside all roles Sees only permitted rows; no-role user sees nothing
Refresh Trigger a manual refresh and check history Succeeds within the window
Performance Open each page with default filters Meets the target in the spec
Usability Watch a manager find an answer without help Answer found in the first minute

Sign-off records who tested what and on which version. A report with no test record cannot defend its numbers in a quality meeting.

Scenario: A Dashboard That Averaged the Averages

A hospital operations team published a length-of-stay dashboard. A director compared the service line card to a query result and found a gap. The dashboard was higher by more than a day. Nobody had changed the data.

I was the business analyst on the report. I traced the gap in an hour. The report averaged a column of unit-level averages.

BI-2208  |  Service line average LOS on dashboard does not match SQLHigh
EnvironmentLOS dashboard v1, September, service line: Medical
Reported byDirector of operations
ExpectedThe card matches the SQL average for the same filters.
ActualDashboard 5.5 days. SQL 3.8 days.
Root causeThe source view returned one row per unit per month with a precomputed average. The measure averaged those rows, so a 20-discharge unit counted as much as a 100-discharge unit.
FixBring discharge counts and total LOS days into the model, and compute the average as total days divided by discharges.
PreventionAdd a test that compares each ratio measure to SQL for two unit combinations.
Unit Discharges Average LOS Total LOS days
Unit A 100 3.0 300
Unit B 20 8.0 160
Average of averages 5.5
Correct: total days / discharges 120 3.8 460
Averages of averages weight small units too much
-- Before: measure over a precomputed average column
Avg LOS = AVERAGE ( fact_unit_month[avg_los] )

-- After: the view carries additive columns, the measure divides sums
Avg LOS = DIVIDE ( SUM ( fact_unit_month[total_los_days] ), SUM ( fact_unit_month[discharges] ) )

The SQL view needed no change except two additive columns. The fix lived in the model, and the test now sits in the UAT list. Any ratio built on a precomputed ratio deserves suspicion.

Illustrative figures
The hospital, ticket number, and values are a composite from reporting projects. The arithmetic in the table is exact, and the failure is common.

Scenario: A Revenue Dashboard Every Manager Could See in Full

A revenue cycle team built a denial dashboard with row-level security so each facility manager saw only their facility. During a pre-release check, a manager reported seeing totals for every facility.

SEC-1409  |  Facility managers see all facilities on denial dashboardHigh
EnvironmentDenial dashboard v2, production workspace
Reported byFacility manager, during UAT
ExpectedEach manager sees only their facility.
ActualManagers see all 12 facilities, including dollar amounts and denial reasons.
Root causeManagers held the member role in the workspace. Row-level security applies to viewers, so the role did not restrict them.
ContributingReport consumers were added to the workspace directly to save time. No “View as” test from the service side.
FixMove consumers to the viewer role, distribute through an app, and test with a real manager account.
ReviewPrivacy office reviews the access list; no patient identifiers were in the model.
Item Before After
Consumer access Workspace member App audience and viewer role
Row-level security result Bypassed Enforced
Security test Desktop “View as” only Desktop and service tests with real accounts
Access review None Quarterly, signed by the data owner

Two lessons apply to any BI tool. Test security in the environment where users will meet it, and keep identifiers out of the model when the question does not need them. The second lesson limited the damage here.

Where Does the Logic Belong in a SQL Query to Power BI Report?

Defects hide when the same rule lives in three layers. Use the tree below to decide the home for each rule, then write it down in the spec.

What kind of rule is it?
Row-level businessrule or filter
Type fix or renamefor this report
Ratio or total thatresponds to filters
Who may seewhich rows
SQL viewTest grain and counts
Power QueryKeep steps minimal
DAX measureDivide sums, not averages
RLS + rolesTest in the service
Every branch: one home per rule, written in the spec

Performance and Effort: What Slows a Report and What It Costs

A slow report loses its audience faster than a wrong one, because people stop opening it. Most slowness comes from the model, not from Power BI itself. Check these items in order.

Symptom Likely cause What to do
Refresh takes too long Wide tables, unused columns, or a heavy view Select only needed columns; aggregate in the view; check the view’s plan
Visuals load slowly High-cardinality columns, complex measures, many visuals per page Use Performance Analyzer in Desktop; simplify measures; reduce visuals
Transformations do not reach the database Query folding stopped at a step Check “View Native Query” on each step; move the logic into the view
Model file is large Free-text and identifier columns loaded Remove columns the report does not use
Slicers lag Slicer on a column with millions of values Slice on a dimension attribute instead

Query folding means Power Query turns its steps into SQL that runs at the source. When a step breaks folding, Power Query pulls the data into the service and transforms it there. The fix is nearly always to move that step into the SQL view.

Effort and naming conventions

Plan effort by step, not by page. In my projects the SQL view and the tests took as long as the visuals. Ask for time in the estimate for profiling, view tests, security, and UAT. Teams that estimate only “build the dashboard” overrun every time.

Item Convention
Views rpt.vw_[subject] for facts and rpt.vw_[dimension] for dimensions
Model tables fact_[subject] and dim_[name]
Measures Plain business names, grouped in a “Measures” folder
Report files Name, version, and date; keep in version control or a managed library
Metric sheet link Each measure description points to the metric sheet row

Conventions look like overhead until the person who built the report leaves. Then they are the only documentation, and the team that wrote them ships fixes in an afternoon instead of a week.

Templates a Business Analyst Can Reuse

Data source request

Send this to the data owner before you build. It surfaces access and privacy questions while there is still time to answer them.

Field What to write
Report and purpose Name, audience, decision supported
Source objects requested View names, not base tables, where a view exists
Fields needed and why Each field linked to a metric; identifiers justified or removed
Sensitivity PHI, financial, or confidential; minimum necessary rationale
Refresh need Daily, weekly, near real time; cutoff time
Account and access Service account for refresh; named viewers or groups
Approver Data owner and privacy office sign-off

UAT checklist

Check Evidence Owner Done
Every card ties to a SQL query for the same filters Query and screenshot pair QA
Ratios checked for two filter combinations Hand calculation QA
Partial month and empty month behave as specified Screenshots QA
Row-level security tested by role and with real accounts Test log QA and security
Tooltips show definitions; no identifiers appear Review notes BA
Refresh schedule runs after the source load Refresh history Report developer
Users can find the answer to each page question Observation notes BA
Sign-off recorded with version and date Signed spec Business owner

Jira-style story for the report build

REQ-4075  |  Unit manager discharge and LOS dashboardMedium
StoryAs a unit manager, I want my unit’s discharges and average LOS by month, so that I can adjust staffing.
Acceptance 1Given I open the report, when it loads, then I see the last complete month for my units only.
Acceptance 2Given I select a different month, when the page updates, then the cards and chart match the SQL result for that month.
Acceptance 3Given I have no unit assigned, when I open the report, then I see no data.
Data ruleLOS counts midnights between admit and discharge; observation stays and newborns are excluded.
TraceabilityView tests V1-V3, model tests M1-M4, UAT items U1-U8; metric sheet v1.

Role Checklists for Power BI Report Projects

Business Analyst

  • Sign the metric sheet and the report spec before development starts.
  • Request views and access with the data source form, not by message.
  • Own the UAT checklist and the out-of-scope list.
  • Record who approves definition changes after release.

Data Analyst or SQL Developer

  • Build a view at a stated grain and run the grain, count, and orphan tests.
  • Keep patient identifiers out of the view unless the spec requires them.
  • Return additive columns, so ratios can be computed in the model.
  • Version the view with the report.

Report Developer

  • Model as a star with a complete date table.
  • Write measures, not calculated columns, for ratios.
  • Test row-level security as a viewer in the service.
  • Document the storage mode decision and the refresh schedule.

QA Analyst

  • Reconcile each card to SQL, and each SQL view to source.
  • Test empty periods, partial months, and users outside all roles.
  • Retest after every source or model change.
  • Attach evidence to the ticket, never patient values.

Common Mistakes Moving From SQL Query to Power BI Report

Mistake Effect Fix
Opening Power BI before defining the metric Rework when definitions change Sign the metric sheet first
Using SELECT * from base tables Slow refresh and exposed columns Connect to a governed view
Pasting long SQL into the connection Hidden logic, harder tests Move the SQL into a view
Averaging precomputed averages Weighted wrongly Divide sums by counts in a measure
No date table Time comparisons fail or mislead Add and mark a date table
Bidirectional or many-to-many relationships by default Ambiguous filters, double counts Use one-to-many, single direction
Calculated columns for ratios Values do not respond to filters Write measures
Sharing through workspace roles Row-level security bypassed Use viewer role or an app
Scheduling refresh before the source load ends Stale or partial data Schedule after the load completes
No refresh failure alerts Silent stale reports Name an owner and monitor
The mistake I made once
Every card on my dashboard tied to SQL. Then someone filtered to one unit and the average moved the wrong way. I had tested only the unfiltered view. I now test two filter combinations for every ratio.

When I Would Use Power BI and When I Would Use Something Else

Need My pick Why
Interactive departmental dashboard on SQL data Power BI with Import mode Fast, shareable, governed through the service
One-off answer for a single question SQL query, then Excel Faster than building a model
Pixel-exact printed report or statement Paginated report tool Layout control for print and PDF
Near-real-time operational view DirectQuery or a purpose-built tool Freshness outweighs speed
Organization already standardized on Tableau Tableau Support and skills already exist
Analysis needing statistics or scripting Python, then publish results Power BI shows results; it is not the best place to compute them

Your employer’s standard usually decides the tool. The workflow in this article holds for Tableau as well: define, query, test, model, secure, publish. The which tool to master first article compares the tools by task.

Edge Cases That Break Report Workflows

Edge case Why it breaks the report How to handle it
Source load finishes late Refresh runs on incomplete data Trigger refresh from the load job or add a completeness check
Discharge corrections after month end Closed months change Show “as of” time and decide when months lock
Time zones and daylight saving Dates shift near midnight Convert in the view and state the basis
Merged or reassigned departments History splits across names Use a dimension with effective dates
Very large fact tables Import size and refresh time grow Aggregate in the view or use incremental refresh
Users share exports Data leaves the controlled workspace Disable export for sensitive reports and log access
Personal gateways Refresh stops when a laptop sleeps Use an enterprise gateway and service account
AI-written DAX or SQL Plausible and wrong Reconcile output to SQL before release

Healthcare data adds a standing constraint. The model may be small, yet it can hold identifiers that make it PHI. Classify the semantic model, limit the audience, and review exports with the privacy office.

Keeping the Report Correct After Release

A published report is a living product. Sources change, definitions change, and users find new questions. Treat the report like any other system with a support plan.

Activity Frequency Owner
Check refresh history and failures Daily (alerts) Report developer
Rerun view tests and reconcile to source Monthly QA
Review access list and roles Quarterly Data owner
Review usage and retire unused pages Quarterly Business analyst
Handle definition changes through tickets As needed Business analyst and owner

For more SQL patterns behind these views, return to the SQL for IT Analysts hub.

Questions Analysts Ask About Moving From SQL Query to Power BI Report

Can I paste my SQL query straight into Power BI?

Yes, Power BI accepts a SQL statement when you connect. For governed reports I prefer a view. The view is reviewable, testable, and reusable, and it keeps logic out of the report file.

Should the report calculate or should SQL calculate?

Let SQL apply row-level rules and return additive columns. Let DAX compute ratios and totals that respond to filters. Putting aggregates in SQL and then aggregating again in the report is how averages of averages happen.

Import or DirectQuery for a hospital dashboard?

Import fits most. Daily refresh is enough for staffing and quality views, and Import is faster. Choose DirectQuery when freshness or data size forces it, and tune the source first.

Does a business analyst need to learn DAX?

You need to read it. Knowing what a measure does lets you review the logic against your metric sheet. Writing complex DAX is a developer task on most teams.

Run This Before Your Next Report Build

Take one report in development. Pick one ratio card and two filter combinations. Compute the same ratio in SQL by dividing totals. If the card and the query disagree in either combination, fix the model before anyone sees the report.

Download the SQL-to-Power BI Report Workflow Checklist and Report Spec Template (PDF)
Twelve-step workflow, metric sheet, report spec, Import vs DirectQuery guide, DAX starters, and UAT checklist on two printable pages.

Download the PDF

Sources and Further Reading

  • Microsoft Power BI documentation. Official guidance on storage modes, models, row-level security, gateways, and refresh.
  • DAX reference. Official function reference for the measures used here.
  • Microsoft Learn, Power BI row-level security and workspace roles articles (learn.microsoft.com). Confirm current role behavior for your tenant.
  • U.S. Department of Health and Human Services, HIPAA minimum necessary guidance. Applies to the fields in views and models.

Ticket numbers and figures in the scenarios are illustrative composites. Table and column names follow standard Epic Clarity and vary by version. Power BI features and licensing change often, so confirm them against current documentation. Run every query in a non-production environment first.

Scroll to Top