Power BI: calculated aggregate column using related tables - powerbi

I have the following two tables:
I would like to add a calculated column to the Author table showing the total number of pages in all the books the author has written.
In SQL I would solve the problem by writing a view like this (or using that code in a trigger to populate the calculated column):
SELECT
"Author"."Author ID"
(SELECT sum("Page count") FROM Book WHERE "Author ID" = "Author"."Author ID") AS "Total pages"
FROM "Author";
How to achieve something like that in Power BI?

Since you want to add the column to the dimension table (one side of the one-to-many relationship) you'll have to use RELATEDTABLE() instead of the RELATED() function:
Page Count = SUMX(
RELATEDTABLE(Book),
Book[Page Count]
)
The row context in your calculated column gets transfered to a filter context in the fact table (Books). This feature is know as context transition.
Of cause your SQL would rather return a table like this one:
Author Pages =
SELECTCOLUMNS(
Author,
"Author ID", Author[Author ID],
"Page Count", SUMX(
RELATEDTABLE(Book),
Book[Page Count]
)
)
However, if you are just interested in visualizing the numbers you don't need any of the above expressions, but just have to drag Author ID and Page Count into a Table visual.

Related

Filter Table by Values from two other tables in Power BI Measure

In my current report in PowerBI I need data from a table "Booking Data" with bookings of users that were not planned. These are to be matched with data from table "Project Members" and entered in a row from table "Projects" as a total Count at the right ID.
Currently I get the number of users who have booked to the respective ID. Now I need to match these names with the "Project Members" fields and if there are not in the "Project Members" table then they need to count.
I got the Tables "Project Members", "Projects" and "Booking Data".
My current outcome:
not Planned User =
CALCULATE(
DISTINCTCOUNT('Booking Data'[User]),
FILTER(
'Booking Data',
Projects[ID] = 'Booking Data'[ID]
)
)
I am now missing the " matching " with the Project Members table, but so far everything has run on error for me.
This is how I would get that "anti-join" counting. Filter 'BookingData' down to the records that have no match between BookingData[User] and ProjectMember[Project Member]. Then distinct count the user.
When you set this measure alongside a Project column in a visual, you will get the grouping effect that you're after.
NotPannedUser =
CALCULATE (
DISTINCTCOUNT ( BookingData[User] ),
FILTER (
BookingData,
NOT BookingData[User] IN VALUES ( ProjectMember[Project Member] )
)
)

PowerBI - How to show only 10 categories and wrap the rest on "Others"

I have a customer service ticket list and need to build a report with it, one of the charts must be a "Qty per motive" and the problem is that I have too many motive to show on a chart, so I want to show let's say 10 of them and wrap the rest on a "Others" categories.
I've found some posts showing hot to do this with values like Sales, but I couldn't figure out how to make it work with a count on my data.
the structure of the data is like
ClientID | Ticket ID | Date | Motive | Description
In the posts that I've found the solution involves a SUM() and then sorting by the SUM() column, but I don't have a value column, I need to count per motive
There are a couple of ways to doing that.
New group
use built-in PBI feature that you have to manually set up. Right-click on a column name in the Fields section and chose New group. A new window will pop up. There, you have to choose the categories you want to label as others. A new field (Column name (groups)) will appear in your table. This method requires you to decide arbitrarily which columns you want to be displayed.
Create calculated table
You could create a brand new Calculated table in your model that is going to set new labels based on the total quantity. In that case, the labels will dynamically change rather than being static. If new motive comes to the model and its quantity will be in TOP N then it will be visible on the chart. This solution creates a separate table that you have to connect via relationship with your main table later.
Select Calculated table on the ribbon and then write DAX:
TopNCategories =
VAR keepLabels = 3
VAR tbl =
ADDCOLUMNS(
VALUES( 'Product'[Brand] ),
"#TotalSales", CALCULATE( [Sales Amount] )
)
VAR addRank =
ADDCOLUMNS(
tbl,
"#Rank",
RANKX(
tbl,
[#TotalSales],
,
DESC
)
)
VAR result =
SELECTCOLUMNS(
addRank,
"BrandKey", 'Product'[Brand],
"NewLabel", IF( [#Rank] <= keepLabels, 'Product'[Brand], "Others" )
)
RETURN
result
Calculated column
If you don't want to create another instance in your model, you can use the above logic to create a set of Calculated column in your main table instead. Depends on your model size and cardinality, this solution may have an impact on the performance of the whole report.

How do I manipulate measure values based on 2 other dimension tables

Power BI newbie here and I'm trying to figure how to craft my DAX to manipulate my measure values based on certain criteria in the other two tables.
Currently I have 2 separate tables which are joined by a One to Many relationship and a separate Measures table. (Total Sales Price is computed as sum of Sales Price)
My aim is to create a new measure where Total Sales Price is multiplied by 1.5x when DIM_Product_Type[Product Category] = "High".
New Measure =
CALCULATE (
SUM ( FACT_PriceDetails[Sales Price] ),
FILTER ( DIM_Product_Type, DIM_Product_Type[Product Category] = "High" )
) * 1.5
However this returns no values in my visual and I'm trying to discern if its a matter of the table joins or the DAX expressions.
Thank you for your time!
Your measure seems good.
It will select only those products with a Product Category of "High" and multiply them by 1.5 to give you result. i.e. Give me the sum of all "High" Product category Price details multiplied by 1.5.
What you need to check is:
Product Serial Numbers match across the two tables
Your Product Category does indeed contain the category "High"
You have entries in FACT_PriceDetails that link to a DIM_Product_Type that has a category of "High"
Check you have not set any filters that could be hijacking your results (e.g. excluding the "High" product category product type or the realated fact/s)
Option-1
You can do some Transformation in Power Query Editor to create a new column new sales price with applying conditions as stated below-
First, Merge you Dim and Fact table and bring the Product Category value to your Fact table as below-
You have Product Category value in each row after expanding the Table after merge. Now create a custom column as shown below-
Finally, you can go to your report and create your Total Sales measure using the new column new sales price
Option-2
You can also archive the same using DAX as stated below-
First, create a Custom Column as below-
sales amount new =
if(
RELATED(dim_product_type[product category]) = "High",
fact_pricedetails[sales price] * 1.5,
fact_pricedetails[sales price]
)
Now create your Total Sales Amount measure as below-
total_sales_amount = SUM(fact_pricedetails[sales amount new])
For both above case, you will get the same output.

Sorting date filter in DESC order in Power BI

I have a date filter for my dashboard and depending on which end of month date the user selects the dashboard displays the appropriate values for the selected month and all of that works correctly. However I would like my date filter to be sorted in DESC order for the user so they do not have to scroll down to the bottom to get the most recent month. I have sorted the dataset in DESC order for the query tied to my dashboard, I have gone to the DATA tab within Power BI and sorted the dataset in DESC order but no matter what I try the filter will not sort in DESC order. Any help is much appreciated.
Unfortunately in page level filters there is no option to sort date to descending order.
One option is to use a Date slicer and sort it descending.
But if you cant have date slicer then a work around is there to implement this.
For this you need to create two calculated columns. One a duplicate column of your date field and another to sort this field.
SortCol = Table[EOM Date]*-1
EOMDateCopy=LEFT([EOM Date],LEN([EOM Date]))
Sort the EOMDateCopy column with SortCol and drag EOMDateCopy in your page level filter.
Best Regards,
Shani
My suggestion is to build your own Calendar table. In "Data" View, create a new Table by writing DAX similar like this:
Calendar =
VAR _MinDate = MIN('YourFactTable'[Date])
VAR _MaxDate = MAX('YourFactTable'[Date])
VAR _BaseCalendar = CALENDAR(_MinDate,_MaxDate)
RETURN
GENERATE(
_BaseCalendar,
VAR _BaseDate = [Date]
VAR _Year = YEAR(_BaseDate)
VAR _Month = MONTH(_BaseDate)
VAR _Quarter = QUARTER(_BaseDate)
VAR _Day = DAY(_BaseDate)
RETURN
ROW (
"Calendar Year", _Year,
"Calendar Month", _Month,
"Calendar Year-Month", _Year&"-"&IF(LEN(_Month)=1,"0"&_Month,_Month),
"Calendar Quarter", FORMAT(_Quarter,"\Q0"),
"Date Order", 9999 - (_Year+_Month+_Day)
)
)
"Date Order", 9999 - (_Year+_Month+_Day) create a descending order for your date.
Next, build a relationship between your Calendar table and your Fact table by relating the "Date" column of your Calendar table and your date column (version_no in my case) of your Fact table. Make sure these two columns have exactly the same date format.
Finally, click on the column and set "Sort by column" as Date Order
You will see your date filter is sorted in desc.
Please make sure your date field is in proper format and then try to sort.
If it is already in date format, please give a bit more details so that we can check.
Best Regards,
Shani

Power BI Rank within Matrix Visual

I've spent many weeks trying to get this to work including a posting at another site. No luck. Not sure what I'm missing.
The following code gets me the table of data that I need. However, I want just the "rank" value and I want it for each row within a matrix visual.
First some background, the PowerBI page has slicers on dates and "base" product. Any given product may be sold in multiple countries. All carry the same base product suffix with a country-specific prefix.
The matrix in question displays several aspects of all the product variants for the selected base product. I want to show where each variant ranks (unit sales) within its country.
VAR tblCountrySales =
SUMMARIZE (
FILTER(
tblSalesUnits,
RELATED(tblProducts[Country])="US"
),
tblProducts[ProdID],
"Total Sales", SUM ( tblSalesUnits[Units] )
)
RETURN
ADDCOLUMNS (
tblCountrySales,
"ProductRank", RANKX ( tblCountrySales, [Total Sales] )
)
Is there a way to either pull just the rank for a single product from the above code, or, better yet, a DAX pattern that will get me the rank by unit sales of each product variant within its respective country?
I've use these statements to successfully get the product ID and country for each row within the visual.
VAR ProdSales = SUM(tblSales[Units])
VAR ProdCountry = SELECTEDVALUE(tblProducts[Country])
Any help is greatly appreciated. I assume I'm missing something with row context within the visual as a simple COUNTROWS on the table expressions above always returns "1". Being new to PowerBI and DAX I'm still trying to grasp the nuances of filter and row contexts.
The products table contains data like...
ProdID.....BaseID....Name...Country
7190...........7190.....xxxx.....US
150207190......7190.....XXXX....Panama
241807190......7190.....xxxx.....Spain
The sales table contains data like...
ProdID......SalesMonth......Units.....USD
7190........July 2010.......4563....$23491.00
150207190...July 2010.......2543....$16235.00
241807190...July 2010.......1263....$8125.00
There is a dates table as well that links the SalesMonth to the usual selection of date display formats. The two tables above are linked via ProdID, though the visuals are sliced by the BaseID. I'd attach a picture, but don't have permissions to do so.
With some more tinkering I found this solution.
Country Rank =
VAR ProdSales = SUM(tblSales[Units])
VAR ProdCountry = SELECTEDVALUE(tblProducts[Country])
VAR tblCountrySales =
SUMMARIZE (
FILTER(
ALLEXCEPT(tblProducts,tblProducts[BaseID]),
tblProducts[Country]=ProdCountry
),
tblProducts[ProdID],
"Total Sales", SUM ( tblSales[Units] )
)
RETURN
IF(ProdSales>0,COUNTROWS(FILTER(tblCountrySales,[Total Sales]>ProdSales))+1,BLANK())