find percentage per unique fields value in a long-format table in powerbi dax - datatable

I have the following snip of a table in power bi:
columns: ['id','fields','io','status','value']
I would like to calculate for each unique value of the column field per id with a condition that the status value is complete.
+----+---------+---------+-----+
| id | field | status | % |
--------------------------------
| 112| zip | complete| 60 |
| 112| gender | complete| 54 |
...
| 245| zip | complete| 85 |
+----+=--------+---------+-----+
the idea is (sum of complete) / (sum of complete+missing+error) per id.
I am not sure how to approach this with a long format table.

try this :
Completed % =
CALCULATE (
SUM ( 'Table (2)'[value] ),
ALLEXCEPT ( 'Table (2)', 'Table (2)'[id], 'Table (2)'[fields] ),
'Table (2)'[status] = "Complete"
)
/ CALCULATE (
SUM ( 'Table (2)'[value] ),
ALLEXCEPT ( 'Table (2)', 'Table (2)'[id] )
)

You can use this code as a measure:
Completed_Percent =
VAR SummaryTable =
ADDCOLUMNS (
FILTER (
SUMMARIZE ( Table1, Table1[id], Table1[fields], Table1[status] ),
Table1[status] = "complete"
),
"%",
DIVIDE (
100 * CALCULATE ( SUM ( Table1[value] ) ),
CALCULATE ( SUM ( Table1[value] ), ALL ( Table1 ) )
)
)
VAR Result =
SUMX ( SummaryTable, [%] )
RETURN
Result
Then Create a table or Matrix, Put [id], [field],[status] into row area, and put "Completed_Percent" measure in the value area. Done!
If we test it:

Related

how to compute the growth rate in Power Bi using Dax?

I want to have a column in power bi showing the growth rate of sales. I have a table like
year
count
1395
123
1396
232
1397
23
1398
908
1399
678
1400
34
the growth rate is (this year - previous year)/previous year
could you please guide me how I can do this?
When I use the growth the data is like below
You can add a calculated column like this:
growth =
VAR _currentcount = 'Table'[count]
VAR _currentyear = 'Table'[year]
VAR _previouscount =
CALCULATE (
SELECTEDVALUE ( 'Table'[count] ) ,
ALL ( 'Table' ) ,
'Table'[year] = _currentyear - 1
)
RETURN
IF (
NOT ISBLANK ( _previouscount ) ,
DIVIDE ( _currentcount , _previouscount ) - 1
)
or a measure like this, to be used with your year dimension:
growth_measure =
VAR _currentcount = SELECTEDVALUE ( 'Table'[count] )
VAR _currentyear = SELECTEDVALUE ( 'Table'[year] )
VAR _previouscount =
CALCULATE (
SELECTEDVALUE ( 'Table'[count] ) ,
ALL ( 'Table' ) ,
'Table'[year] = _currentyear - 1
)
RETURN
IF (
NOT ISBLANK ( _previouscount ) ,
DIVIDE ( _currentcount , _previouscount ) - 1
)
Giving this result:
All depending on your needs.

How do you repeat rows in a table multiple time

I created a table a DAX Studio and want to repeat all the rows (with all the columns) in a new table multiple times; to my choosing.
//create temp table of Historic Facilities for all annual groups 1 to 3
TABLE HistFac =
ADDCOLUMNS ( FacSchHist,
"Rank", RANKX ( FacSchHist, [WtAvg] ),
"Annual Group", (RANKX ( FacSchHist, [WtAvg] ) - FLOOR((RANKX ( FacSchHist, [WtAvg] ) - 1) /3 * 3,3)))
EVALUATE
NonHistFac
ORDER BY [Annual Group],
[WtAvg] DESC
I want the maintain the original order in the repeated list. There are obviously many ways to construct a table (see code above); however, how does one repeat the list of rows?
Thanks you for any suggestions.
Try to remove the filters that are affecting the measure inside RANKX because of the context transition coming from the table provide in the first argument of GENERATE
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
ADDCOLUMNS (
FacSchHist,
"#Rank",
RANKX (
FacSchHist,
CALCULATE ( [WtAvg], REMOVEFILTERS ( TableSupliedInTheFirstArgument ) )
)
),
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
Or simply use variables to compute in a different filter context.
DEFINE
TABLE HistFac =
VAR RankedTable =
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) )
VAR SomeCalculationOnRankedTable =
ADDCOLUMNS (
RankedTable,
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
RETURN
GENERATE ( { 1, 2, 3 }, SomeCalculationOnRankedTable )
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
You can use GENERATE for repeating the rows:
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
FacSchHist,
"Rank", RANKX ( FacSchHist, [WtAvg] ),
"Annual Group",
(
RANKX ( FacSchHist, [WtAvg] )
- FLOOR ( ( RANKX ( FacSchHist, [WtAvg] ) - 1 ) / 3 * 3, 3 )
)
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
A better way to write this code will be to use nested ADDCOLUMNS:
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) ),
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
AntrikshSharma - I will give those a try now , appreciate your guidance.
Okay, the code worked fine; but uncovered a problem. After the initial ranking of the list, and before the replication - I do not want to continue ranking.
In other words, I want the initial ranked-list to be reproduced 3x without any further ranking; just have each duplicated occurrence appear after the initial list in the exact order.
If the initial list was 12345, then 12345,12345,12345 - thank you for the more efficient code as well.
AntrikshSharma, your comment and code, "Or simply use variables to compute in a different filter context" is genius. The code performed as expected. The problem I'm experiencing is with the UNION of the two tables "NonHistFac" and "HistFac". I will provide an image to explain then the most current code.
15yr cycle of Hist & NonHist Facilities
The image shows the goal. combine the NonHistFac (all surveyed every 5yrs) with the HistFac (all surveyed every 3yrs). The original ranking must be maintained (this is currently met.)
Here is the problem. The numbers within the image are the Values as produced by the GENERATE function. When the tables are combined and the NonHistFac are mixed with the HistFac, they are not evenly distributed throughout the 1 to 5 Values.
What appears in Values 4 and 5 is obviously the remaining HistFac. I need to have the entire combination distributed from 1 to 5; or as shown, over the 15 year cycle.
Thank you.
// produce non-historic table with additional columns and replicate all rows 3x
TABLE NonHistFac =
VAR NonHistRankedTable =
ADDCOLUMNS ( FacSchNonHist, "#Rank", RANKX ( FacSchNonHist, [WtAvg] ) )
VAR NonHistAnnualizedRankedTable =
ADDCOLUMNS (
NonHistRankedTable,
"Annual Group",
[#Rank] - FLOOR ( ( [#Rank] - 1 ) / 5 * 5, 5 )
)
RETURN
GENERATE ( { 1, 2, 3 }, NonHistAnnualizedRankedTable )
// from the FLOOR & GENERATE functions, 5 x 3 = 15 (this is a 15 year cycle)
//produce historic facility table with additional columns and replicate all rows 5x
TABLE HistFac =
VAR HistRankedTable =
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) )
VAR HistAnnualizedRankedTable =
ADDCOLUMNS (
HistRankedTable,
"Annual Group",
[#Rank] - FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
RETURN
GENERATE ( { 1, 2, 3, 4, 5 }, HistAnnualizedRankedTable )
// from the FLOOR & GENERATE functions, 3 x 5 = 15 (this is a 15 year cycle)
// combine the tables NonHistFac & HistFac to create one-table representing a 15 yr cycle
VAR FacSchUnion =
UNION(
NonHistFac,
HistFac
)
VAR FacSch15yr =
DISTINCT(FacSchUnion)
EVALUATE
FacSch15yr
ORDER BY [Value],
[Annual Group],
[WtAvg] DESC

Aggregate a PREVIOUSMONTH measure using SUMX when table has no row in current month

I am trying to build an overview of employees that are in service per month, the number of employees that went into service and the number of employees that left that month.
I have monthly overviews of all employees that are in service, which looks like this:
+----------+----------+------------+
| date | Employee | Department |
+----------+----------+------------+
| 1/1/2019 | A | Sales |
| 1/1/2019 | D | Projects |
| 2/1/2019 | A | Sales |
| 2/1/2019 | B | Sales |
| 2/1/2019 | C | Marketing |
| 2/1/2019 | D | Projects |
| 3/1/2019 | A | Marketing |
| 3/1/2019 | B | Sales |
| 3/1/2019 | C | Marketing |
| 3/1/2019 | D | Projects |
| 4/1/2019 | A | Marketing |
| 4/1/2019 | B | Sales |
+----------+----------+------------+
To calculate the number of active employees in a month I use the measure:
# Employees = COUNTROWS(Employees)
The idea is to use the PREVIOUSMONTH expression to find the number of employees last month and compare it with this month:
# Employees Last Month = CALCULATE([# Employees],PREVIOUSMONTH(DateTable[Date]))
The net inflow/outflow per month is then easily calculated using:
Inflow/Outflow = [# Employees] - [# Employees Last Month]
throwing these in a table per employee gives me the overview that I expect:
I would now want to sum per month all of the of the employees with inflow/outflow = 1 as the inflow and the employees with inflow/outflow = -1 as the outflow. This is where I am running into problems.
My inflow measure seems to work fine:
Inflow =
SUMX (
FILTER (
ADDCOLUMNS (
CROSSJOIN ( VALUES ( DateTable[MonthSort] ), VALUES ( Employees[Employee] ) ),
"IO", [Inflow/Outflow]
),
[IO] = 1
),
[IO]
)
but the outflow measure does not return anything:
Outflow =
SUMX (
FILTER (
ADDCOLUMNS (
CROSSJOIN ( VALUES ( DateTable[MonthSort] ), VALUES ( Employees[Employee] ) ),
"IO", [Inflow/Outflow]
),
[IO] = -1
),
[IO]
)
it seems that in the context of an employee that does not have data in a specific month the VALUES(Employee[Employee]) expression returns nothing (using the test measure) which might explain the problem:
TestEmployee = MAX(Employee[Employee])
Is there anything I am missing? as a calculated table the expressions seem to work fine.
Introduce an employee dimension, with just the attributes of the unique employees (E.g. their ID, their name - anything that is not changing about them). Very explicitly, that dimension should not have department, because department is changing over time for employees.
In =
COUNTROWS (
FILTER (
VALUES ( 'DimEmployee'[Employee] ),
[Inflow/Outflow] = 1
)
)
Out =
COUNTROWS (
FILTER (
ALL ( 'DimEmployee'[Employee] ),
[Inflow/Outflow] = -1
)
)
You were spot on about the employee not existing in the context of a specific date. Since 'DimEmployee' is date-context-free, this doesn't matter.

How to distinctly count customer IDs that visited a store in a given quarter only if the same customer ID visited in the previous quarter

I have a table
+-----------+----------+--------+-------+---------+
|Customer ID|Visit Date|Category|Product|Served by|
+-----------+----------+--------+-------+---------+
|1001 |03/17/2019|A |P11 |Jone Doe |
|1003 |03/17/2019|D |P12 |Jone Doe |
|1006 |03/15/2019|C |P13 |Jone Doe |
|1009 |03/10/2019|G |P14 |Jone Doe |
|1011 |12/12/2018|H |P15 |Foo Bar |
|1003 |11/11/2018|D |P16 |Foo Bar |
|1006 |09/10/2018|C |P17 |Foo Bar |
|1009 |10/10/2018|G |P18 |Foo Bar |
+-----------+----------+--------+-------+---------+
there are 4 customers but only 2 (1003 and 1009) visited in the previous quarter.
I used DATESINPERIOD but it counts all distinctly between the preceding quarters (I have a designated date table).
1st approach
customers_count =
CALCULATE (
DISTINCTCOUNT[Customer ID],
DATESINPERIOD (
'Calendar'[Date],
ENDOFQUARTER ( 'Calendar'[Date] ),
-2,
QUARTER
)
)
2nd approach
customers_count 2Q =
VAR customers_count_1 =
DISTINCT ( FILTER ( VALUES ( Orders[Customer ID] ) ) )
VAR customers_count_2 =
CALCULATETABLE (
DISTINCT ( FILTER ( VALUES ( Orders[Customer ID] ) ) ),
DATEADD ( 'Calendar'[Date], -1, QUARTER )
)
RETURN
COUNTROWS ( INTERSECT ( customers_count_1, customers_count_2 ) )
The expected count is 2 for the last quarter.
Your second approach looks reasonable. Try it without DISTINCT and FILTER.
customers_count 2Q =
VAR customers_count_1 =
VALUES ( Orders[Customer ID] )
VAR customers_count_2 =
CALCULATETABLE (
VALUES ( Orders[Customer ID] ),
DATEADD ( 'Calendar'[Date], -1, QUARTER )
)
RETURN
COUNTROWS ( INTERSECT ( customers_count_1, customers_count_2 ) )
The VALUES function returns a list of distinct values of its column argument that are within its filter context.

How to pass a filtered table to RankX

I would like RankX to rank products for Var2 and only consider/see products who have a value for Var1 (so only A and B and not C).
Here is an example datamodel including the resulting pivottable
And here are the measures I use:
SUM Value = SUM ( Data[Value] )
Var1 Check = CALCULATE ( COUNTROWS ( Data ), Variable[Variable] = "Var1" )
RankX = RANKX ( ALL ( 'Product' ), [SUM Value] )
RankX Filter = IF ( ISBLANK ( [Var1 Check] ), BLANK (), [RankX] )
The idea is that my filtered RankX function (RankX Filter) shows 2 instead of 3 for Product B as only A and B should be considered.
Using DAX Studio I managed to filter my product table accordingly but I don't know whether this the right approach nor how to pass that filtered table to a RankX function.
FILTER (
ADDCOLUMNS (
'Product',
"Var1Check", CALCULATE ( COUNTROWS ( Data ), Variable[Variable] = "Var1" )
),
[Var1Check] = 1
)
You should just be able to put the filtered table as the first argument in your RANKX function. Something along these lines:
RANKX ( FILTER ( 'Product', Variable[Variable] = "Var1" ), [SUM Value] )

Resources