DAX / PP Aggregate a variable project margin down a column - powerpivot
I need a solution similar to this:
DAX running total (or count) across 2 groups
However slightly more complex.
I have the following:
(apologies for the layout - i can't post pictures)
Name Date Monthly Rev Total Rev Margin( % Rev)
Proj 1 1/08/2014 0 7000 15%
Proj 1 1/09/2014 1000 7000 15%
Proj 1 1/10/2014 1000 7000 15%
Proj 1 1/11/2014 1000 7000 15%
Proj 1 1/12/2014 0 7000 15%
Proj 1 1/01/2015 0 7000 15%
Proj 1 1/02/2015 2000 7000 15%
Proj 1 1/03/2015 2000 7000 15%
Proj 2 1/11/2014 0 16000 10%
Proj 2 1/12/2014 1500 16000 10%
Proj 2 2/12/2014 1500 16000 10%
Proj 2 3/12/2014 1500 16000 10%
Proj 2 4/12/2014 1500 16000 10%
Proj 2 5/12/2014 2000 16000 10%
Proj 2 6/12/2014 2000 16000 10%
Proj 2 7/12/2014 0 16000 10%
Proj 2 8/12/2014 2000 16000 10%
Proj 2 9/12/2014 2000 16000 10%
Proj 2 10/12/2014 2000 16000 10%
Monthly rev is the revenue received in a month, total is the total project value and margin is the percentage of revenue. The table is linked to a dates table by Date.
I need to show margin by date (there are other descriptive columns in the table for slicing) however the margin calc is not straightforward.
In an excel table it would look something like this:
Cumm simple margin | Completion| Cumm complex margin | Margin earnt
0 0% 0 0
150 20% 30 30
300 40% 120 90
450 60% 270 150
450 60% 270 0
450 60% 270 0
750 80% 600 330
1050 100% 1050 450
0 0% 0 0
150 11% 17 17
300 22% 67 50
450 33% 150 83
600 44% 267 117
800 56% 444 178
1000 67% 667 222
1000 67% 667 0
1200 78% 933 267
1400 89% 1244 311
1600 100% 1600 356
Where:
Simple margin is calculated on a cumulative basis as % of monthly Rev
Percentage complete of the project is calculated based on "active" months where revenue is earned
Cumulative simple margin is multiplied by the % complete
Actual margin earned in a particular month is the difference between two months.
Note that Monthly revenue is not necessarily continuous.
No idea how to recreate this in power pivot, any suggestions would be well received.
Cheers
Assuming
That your Project 2 data should run monthly from 1/11/2015 to 1/09/2015 (rather than individual December dates)
You have your data in a table called 'ProjectMargins'
Your DateDim table is called 'Reporting Dates'
Then these are the DAX Measures you need (although there may be simpler methods for achieving these results):
[MonthlyRev]:=SUM(ProjectMargins[Monthly Rev])
[ActiveMonth]:=CALCULATE(COUNTROWS('ProjectMargins'),FILTER('ProjectMargins',[MonthlyRev]>0))
[AllActiveMonths]:=CALCULATE([ActiveMonth],ALL('Reporting Dates'[Date]))
[Completion]:=DIVIDE(CALCULATE([ActiveMonth],FILTER(ALL('Reporting Dates'[Date]),'Reporting Dates'[Date] <= MAX(ProjectMargins[Date]))),[AllActiveMonths])
If you need to calculate TotalRev, from your Monthly Rev, Rather than it appearing in the original source table:
[TotalRev]:=IF(ISBLANK(MAX(ProjectMargins[Margin( % Rev)])),BLANK(),CALCULATE([MonthlyRev],ALL('Reporting Dates'[Date])))
[Rev%]:=MAX(ProjectMargins[Margin( % Rev)])
[Cumm Simple Margin]:=CALCULATE([MonthlyRev]*[Rev%],FILTER(ALL('Reporting Dates'[Date]),'Reporting Dates'[Date] <= MAX(ProjectMargins[Date])))
[Cumm Complex Margin]:=[Completion]*[Cumm Simple Margin]
[Previous Month Cumm Complex]:=CALCULATE([Cumm Complex Margin], DATEADD('Reporting Dates'[Date],-1,MONTH))
[Margin Earnt]:=IF([Cumm Complex Margin]>0,[Cumm Complex Margin]-[Previous Month Cumm Complex],BLANK())
NOTE: This assumes that the margin is never negative.
Ensure that the date field from the DateDim table is used in your pivot, not the date field from the Fact table.
Related
Cumulative over table rows with condition Oracle PL/SQL
I have two tables: Employees: employee_id field max_amount 3 a 3000 4 a 3000 1 a 1600 2 a 500 4 b 4000 2 b 4000 3 b 1700 ordered by employee, field, amount desc. Amounts (pol, premia,field): pol premia field **assign_to_employee** 11 900 a 3 44 1000 a 3 55 1400 a 4 77 500 a 3 88 1300 a 1 22 800 b 4 33 3900 b 2 66 1300 b 4 Assign Stats Table: employee_id field max_amount true_amount remain 3 a 3000 2400 600 4 a 3000 1400 1600 1 a 1600 1300 300 2 a 500 0 500 4 b 4000 2100 1900 2 b 4000 3900 100 3 b 1700 0 1700 The output : assign_to_employee field (merged to amounts table). Algoritem wise : The method is to assign pol's to employees until the premia needs to be added to the cumulative_sum is bigger then the max amount per employee listed in the employees table. You always start with the employess with most max amount until you cannot add any other pols to the employee. I start with the employees with the grater max_amount per field. I keep doing this until no pols remains to be assign. Can you help me solve this? Thank you.
plsql sum another table values to joined tables
I have 3 tables.First table is student.Second is student_detail and last one special_codes. student table studentname | invoiceno |tax |invoiceamount Paul 10 500 1950 Georghe 20 1000 6850 Mary 30 1500 1900 Messy 40 2000 7050 studentdetail invoiceno | code | product | amount 10 101 pencil 100 10 102 rubber 350 10 103 bag 1500 20 108 wheel 5000 20 109 tv 1500 20 110 ps 300 20 111 mouse 50 30 103 bag 1500 30 105 keyboard 400 40 111 mouse 50 40 112 car 7000 I can join these two table like this and get result table select s.studentname,s.tax,s.invoiceamount,st.product,sum(st.amount) from student s, studentdetail st where s.invoiceno = st.invoiceno group by s.studentname, s.tax, s.invoiceamount, st.product result table studentname tax invoiceamount product amount Paul 500 1950 bag 1500 Paul 500 1950 pencil 100 Paul 500 1950 rubber 350 Messy 2000 7050 car 7000 Messy 2000 7050 mouse 50 Mary 1500 1900 bag 1500 Mary 1500 1900 keyboard 400 Georghe 1000 6850 mouse 50 Georghe 1000 6850 ps 300 Georghe 1000 6850 tv 1500 Georghe 1000 6850 wheel 5000 Last table is special codes.It contains only one column which is called code specialcodes table code 101 102 113 104 105 110 111 What i want to do is to look up studentdetail table and to find codes that are same in specialcodes.Then to sum amount values and write sum to result table as another column.Result table should be like that result table(final) studentname tax invoiceamount product amount taxexclude Paul 500 1950 bag 1500 450 Paul 500 1950 pencil 100 450 Paul 500 1950 rubber 350 450 Messy 2000 7050 car 7000 50 Messy 2000 7050 mouse 50 50 Mary 1500 1900 bag 1500 400 Mary 1500 1900 keyboard 400 400 Georghe 1000 6850 mouse 50 350 Georghe 1000 6850 ps 300 350 Georghe 1000 6850 tv 1500 350 Georghe 1000 6850 wheel 5000 350
You can use analytic functions rather than GROUP BY and aggregating: select s.studentname, s.tax, invoiceamount, SUM(d.amount) OVER (PARTITION BY s.invoiceno) AS inv_amt_calc, d.product, d.amount, SUM(CASE WHEN c.code IS NOT NULL THEN d.amount END) OVER (PARTITION BY s.invoiceno) AS taxexclude from student s INNER JOIN studentdetail d ON s.invoiceno = d.invoiceno LEFT OUTER JOIN specialcodes c ON (c.code = d.code) Note: You can (and should) calculate the invoice amount from the studentdetails table rather than duplicating the data in the student table and violating Third-Normal Form. Which, for your sample data, outputs: STUDENTNAME TAX INVOICEAMOUNT INV_AMT_CALC PRODUCT AMOUNT TAXEXCLUDE Paul 500 1950 1950 rubber 350 450 Paul 500 1950 1950 pencil 100 450 Paul 500 1950 1950 bag 1500 450 Georghe 1000 6850 6850 tv 1500 350 Georghe 1000 6850 6850 wheel 5000 350 Georghe 1000 6850 6850 ps 300 350 Georghe 1000 6850 6850 mouse 50 350 Mary 1500 1900 1900 bag 1500 400 Mary 1500 1900 1900 keyboard 400 400 Messy 2000 7050 7050 mouse 50 50 Messy 2000 7050 7050 car 7000 50 If you really want a version using GROUP BY then: SELECT s.studentname, s.tax, s.invoiceamount, SUM(d.amount) OVER (PARTITION BY s.invoiceno) AS inv_amt_calc, d.product, d.amount, t.taxexclude FROM student s INNER JOIN studentdetail d ON s.invoiceno = d.invoiceno LEFT OUTER JOIN ( SELECT invoiceno, SUM(amount) AS taxexclude FROM studentdetail WHERE code IN (SELECT code FROM specialcodes) GROUP BY invoiceno ) t ON s.invoiceno = t.invoiceno; db<>fiddle here
Moving Median PostgreSQL with Partition
I'm looking to create a prior rolling 4 quarter Median. Some entries have less than 4 quarters, some have more. I want this by Employee. Needs to account for different tenure for different employees. Result for 2021-1 should represent the prior 4 quarters median (and not account for current quarter). I was able to figure out a rolling average with partitioning but not sure how to tackle a rolling median. Thanks! Employee ID Quarter Sales EXPECTED RESULT A 2020-1 1000 NULL A 2020-2 2000 1000 A 2020-3 3000 1500 A 2020-4 4000 2000 A 2021-1 5000 2500 A 2021-2 4000 3500 B 2020-3 8000 NULL B 2020-4 7000 8000 B 2021-1 6000 7500 B 2021-2 5000 7000 B 2021-3 1000 6500 C 2021-1 5000 NULL C 2021-2 0 5000 C 2021-3 4000 2500
Access the previous row in select
I have a scenario as below --source data departuredttm flight_source flight_destination available_seats 13-07-2016 04:00:00 A B 200 13-07-2016 08:00:00 A B 320 13-07-2016 08:20:00 A B 20 I have a lookup table which tell how many total passengers are there for this source and destinatin whose flights are delayed and needs to adjusted in available seats in source data.lookup table is like this. --lookup table for passenger_from_delayed_flights flight_source flight_destination passengers A B 500 now I have to adjust these 500 passengers in available seats as in source data ---output DepartureDttm flight_source flight_destination AVAILABLE_SEATS PASSENGERS_TO_ADJUST PASSENGER_LEFT 13-07-2016 04:00:00 A B 200 500 300 13-07-2016 08:00:00 A B 320 300 20 13-07-2016 08:20:00 A B 20 20 0 initially passenger to adjust is 500 where we have 200 seats , next 320 seats are available and we have to adjust 300 (500-200) passengers. Please help Thanks
Your expected result is probably wrong, the 2nd flight already has enough seats, so PASSENGER_LEFT should be -20 (or 0). This is a calculation based on a running total: passengers - SUM(available_seats) OVER (ORDER BY departuredttm ROWS UNBOUNDED PRECEDING) AS PASSENGER_LEFT available_seats + PASSENGER_LEFT AS PASSENGERS_TO_ADJUST
Aggregate one measure by another in MS Analysis Services
There is a CUBE with two measures Prices, Volumes and dimension Hours. (The real CUBE is much complex, this is a simplified version.) Hours Prices Volumes 0 0 100 0 10 20 0 20 300 0 40 100 0 50 50 1 0 500 1 20 50 1 25 200 1 40 30 1 50 10 How to aggregate Volumes by Prices and get next result (probably by using MDX query): Prices Volumes 0 600 10 20 20 350 25 200 40 130 50 60