Join us at FabCon Atlanta from March 16 - 20, 2026, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.
Register now!Calling all Data Engineers! Fabric Data Engineer (Exam DP-700) live sessions are back! Starting October 16th. Sign up.
I've written the following below for our audit table which has the potential to have multiple audit entries per faultid per day. I wanted to count the number of tickets that where active per day. This Work's out which is last audit entry for that day. This is table can be filtered by a date period & agent or team slicers connected to a disconnected date tables. This is then filters down list of results showing only the last audit entry of faultid.
As it stand this works fine if used in a table row. If I add this to filter context of table (Only a table) where it equals 1 then it will filter down the correct number of rows.
However Id like to count the number of rows, rather than it work out if each row is correct. I've tried to do SumX or similar which will not work I've also tried Summrizecolumns etc.
I'm guessing it creating a table value and not scalar value. Id like to end up with measure rather than table or caculated column
Hi @locka,
You’re very close. The main things slowing you down / blocking a scalar count are:
- using FORMAT(...) in row filters (it forces string scans and kills indexes),
- relying on row-by-row comparisons instead of a single, set-based filter,
- applying disconnected slicers implicitly instead of mapping them with TREATAS.
Below is a drop-in measure that:
1) works against your condensed FACT_FaultEndOfDayAssignment table,
2) supports disconnected date / agent / team slicers, and
3) returns a scalar count (so you can use it in cards, KPIs, or filters).
Active Tickets (range) - counts tickets that overlap the selected date range, filtered by the disconnected slicers:
Active Tickets (range) := VAR MinDate = MIN ( '@DIM_Date'[Date] ) VAR MaxDate = MAX ( '@DIM_Date'[Date] ) RETURN CALCULATE ( COUNTROWS ( FACT_FaultEndOfDayAssignment ), // overlap: [From] <= Max AND COALESCE([To], +infinity) >= Min KEEPFILTERS ( FILTER ( FACT_FaultEndOfDayAssignment, FACT_FaultEndOfDayAssignment[FromDatetime] <= MaxDate && COALESCE ( FACT_FaultEndOfDayAssignment[ToDatetime], DATE ( 9999, 12, 31 ) ) >= MinDate ) ), // map disconnected slicers TREATAS ( VALUES ( '@DIM_Teams'[AgentTeam] ), FACT_FaultEndOfDayAssignment[AgentTeam] ), TREATAS ( VALUES ( '@DIM_Agent'[AgentID] ), FACT_FaultEndOfDayAssignment[AssignedAgentID] ), // optional status exclusion (faster than IN/FORMAT) KEEPFILTERS ( FILTER ( FACT_FaultEndOfDayAssignment, FACT_FaultEndOfDayAssignment[Status] <> "Rejected" && FACT_FaultEndOfDayAssignment[Status] <> "Cancelled" ) ) )
Active Tickets (per day) — same logic, but when you put it on a daily axis it evaluates per the day in context (no strings/FORMAT):
Active Tickets (per day) := VAR DayStart = SELECTEDVALUE ( '@DIM_Date'[Date] ) VAR DayEnd = DayStart RETURN CALCULATE ( COUNTROWS ( FACT_FaultEndOfDayAssignment ), KEEPFILTERS ( FILTER ( FACT_FaultEndOfDayAssignment, FACT_FaultEndOfDayAssignment[FromDatetime] <= DayEnd && COALESCE ( FACT_FaultEndOfDayAssignment[ToDatetime], DATE ( 9999, 12, 31 ) ) >= DayStart ) ), TREATAS ( VALUES ( '@DIM_Teams'[AgentTeam] ), FACT_FaultEndOfDayAssignment[AgentTeam] ), TREATAS ( VALUES ( '@DIM_Agent'[AgentID] ), FACT_FaultEndOfDayAssignment[AssignedAgentID] ), KEEPFILTERS ( FILTER ( FACT_FaultEndOfDayAssignment, FACT_FaultEndOfDayAssignment[Status] <> "Rejected" && FACT_FaultEndOfDayAssignment[Status] <> "Cancelled" ) ) )
Notes
- No FORMAT calls (huge perf win).
- TREATAS cleanly applies your disconnected slicers.
- Your Power Query “end-of-day” condensation means each FaultId has at most one row per day, so a COUNTROWS after set filters is both correct and fast.
- Keep your existing CROSSFILTER only if you genuinely need to override a relationship; otherwise let the model relationships do the work.
- If you currently use CROSSFILTER(..., Both) in the measure, prefer a proper relationship with the minimal necessary direction. Only keep CROSSFILTER if you’re overriding an inactive/special case.
- If your Date slicer range is large, consider capping the MaxDate to TODAY() (or a data watermark) to prevent accidental “open-ended” windows.
If you’d like, share a tiny PBIX (anonymized) and I can sanity-check the model relationships and confirm you don’t need the CROSSFILTER at all.
If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution.
Hi @locka,
Thank you for the thorough explanation. This helps clarify why I was encountering query limits, and the suggestions for using variables and TREATAS are very useful.
Please reachout to us for more queries
Thank you and continue using Microsft Fabric Community Forum.
Hi @locka,
This behavior is normal for audit history tables. If several records have the same From Date/Time, the one with a To Date indicates a closed event, while the one without a To Date is the most recent and currently active record.
For performance, SUMX works but can be slow since it processes each row individually. A better option is to use a calculated column, such as ActiveFlag, and aggregate with SUM, or change the logic to focus only on the latest entry for each record. This will help improve speed by reducing row-by-row calculations.
Thank you.
Hi @locka,
Just wanted to follow up and confirm that everything has been going well on this. Please let me know if there’s anything from our end.
Please feel free to reach out Microsoft fabric community forum.
Hi @locka,
We strive to make sure every issue gets addressed completely. Still facing issues? Just reply here and we’ll be right with you.
Thank you for being a valued part of the community.
Hi @locka,
Just looping back one last time to check if everything's good on your end. Let me know if you need any final support happy to assist if anything’s still open.
Thank you.
Hi thanks for checking in.
I now have a working measure. Which now works out which tickets area\where active over a period chosen. However I believe it's the reason I'm now getting a lot query exceeds. I'm wondering how best to make the dax more efficient?
FACT_FaultEndOfDayAssignment is now a condensed version of faultassignment history table. In powerquery its only keeping entry with latest Fromdate per day. So now it can only ever have one Faultid & Fromdate the same. Although a ticket can have the same Todate & Fromdate.
Both my DateTable along with my AgentTable & AgentTeamTable have to be disconnected tables as they are linked to multiple fields some in the same table which refer to different dates\people. As agent can create a ticket but a different agent resolve it etc. So this allows use to only need to pick one date, team, agent and then depending the visual is filter accordingly.
Ok if I use my original measure. The sum it via a second measure using
Hi @locka
PFA
Active Count =
VAR MaxDate = MAX('@Dim_Date'[Date])
VAR MinDate = MIN('@Dim_Date'[Date])
RETURN
COUNTROWS(
FILTER(
'FACT_FaultAssignmentHistory',
VAR MaxFromDate =
CALCULATE(
MAX('FACT_FaultAssignmentHistory'[FromDateTime]),
ALLEXCEPT('FACT_FaultAssignmentHistory', 'FACT_FaultAssignmentHistory'[FaultId]),
'FACT_FaultAssignmentHistory'[FromDate] <= MaxDate
&& ('FACT_FaultAssignmentHistory'[ToDate] >= MinDate
|| ISBLANK('FACT_FaultAssignmentHistory'[ToDate]))
)
RETURN
FORMAT('FACT_FaultAssignmentHistory'[FromDateTime], "tttt") = FORMAT(MaxFromDate, "tttt")
&& NOT RELATED('DIM_Statuses'[Status]) IN {"Rejected", "Cancelled"}
)
)
Please let me know if this is what you need
Best regards,
Thanks for the reply
However I now get duplicate faultid I modifed your code slightly to give filter the teams selected, but what I see is duplicates of the faultid. So it's not picking the latest From datatime, which infaltes the count. This what Ive been using: -
Hi @locka
Your current measure returns a table-like result per row and relies on FORMAT to compare dates/times. That works in a table visual but makes it hard to produce a single scalar count. Also, FORMAT converts values to text, which hurts performance and can change filter behavior. The fix is to:
1) compute a row-level "is last per FaultId per day" flag as a measure, and
2) SUM it up over the fact table restricted to the disconnected date range and Agent/Team selections.
Quick solution
Create two measures. The first returns 1 only for the last audit row per FaultId per day within the current filter context. The second counts those rows for the selected date range and Agent/Team filters.
-- 1) Helper measure: returns 1 for the last audit row for a FaultId on a given day
Active Row Flag :=
VAR d = MAX ( 'FACT_FaultAssignmentHistory'[FromDate] )
VAR f = MAX ( 'FACT_FaultAssignmentHistory'[Faultid] )
VAR lastAuditThisDayForFault :=
CALCULATE (
MAX ( 'FACT_FaultAssignmentHistory'[FromDateTime] ),
ALLEXCEPT (
'FACT_FaultAssignmentHistory',
'FACT_FaultAssignmentHistory'[FromDate],
'FACT_FaultAssignmentHistory'[Faultid]
)
)
VAR isAllowedStatus =
NOT ( RELATED ( DIM_Statuses[Status] ) IN { "Rejected", "Cancelled" } )
RETURN
IF (
MAX ( 'FACT_FaultAssignmentHistory'[FromDateTime] ) = lastAuditThisDayForFault
&& isAllowedStatus,
1, 0
)
-- 2) Final scalar measure: counts active tickets (last audit per FaultId per day)
Active Tickets :=
VAR DateFilter = VALUES ( '@Dim_Date'[Date] )
-- Push the disconnected date selection onto the fact table
VAR FactInDateRange :=
CALCULATETABLE (
'FACT_FaultAssignmentHistory',
TREATAS ( DateFilter, 'FACT_FaultAssignmentHistory'[FromDate] )
)
-- Optional: restrict to selected Agents or Teams if either slicer is used
VAR FactFiltered :=
FILTER (
FactInDateRange,
(
ISBLANK ( SELECTEDVALUE ( '@DIM_Agent'[AgentID], BLANK () ) )
&& ISBLANK ( SELECTEDVALUE ( '@DIM_Teams'[AgentTeam], BLANK () ) )
)
|| 'FACT_FaultAssignmentHistory'[AssignedAgentID] IN VALUES ( '@DIM_Agent'[AgentID] )
|| 'FACT_FaultAssignmentHistory'[AgentTeam] IN VALUES ( '@DIM_Teams'[AgentTeam] )
)
RETURN
CALCULATE ( SUMX ( FactFiltered, [Active Row Flag] ) )
Notes and gotchas
- Do not use FORMAT for date/time comparisons; keep them as true date/time values for correct filtering and better performance. See DAX CALCULATE and filter context behavior: CALCULATE, and date filtering with TREATAS: TREATAS.
- ALLEXCEPT retains the grouping by FaultId and FromDate so MAX finds the last FromDateTime within that group: ALLEXCEPT.
- SUMX over the filtered fact table yields a scalar, so you can use it in cards and KPIs.
- If you prefer, you can replace the Agent/Team block with a strict requirement that both slicers must match by removing the first OR branch.
If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution.
Thanks for the reply.
I had to tweak first measure around isnotallowedstatus but I can live with that for now. However second measure just produces blank. The first measure is giving me rows which have 1 against them.
Looking at the second measure I think its because it needs to be looking at tickets which have a date in that period as in they must have been open on that day. So for example yesteday no tickets have that date so they are blank. What it needs to be able to do is have tickets which were open at somepoint over that period: -
Where as I think your measure is assuming it all tickets just have that from date where its quite conceivable that it has an earlier date than that as well.
Also tried to breakdown the value by team in matrix and that made no difference it just gave me a total. Is that not possible?