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