DAX - Different Granularities - ssas

I have a Diff Grain Type Question.
I have a Fact table with 2 measures - Amount and Share_amount
EG
Name Location Amount Share_amount
John Ireland 100 50
John UK 100 50
fred USA 200 200
Bob france 300 150
Bob spain 300 150
I'd like to display the Amount but SubTotal/Total by Share_amount
In the pivot I'd like to see:
John 100
John Total 100
fred 200
Fred total 200
Bob 300
Bob Total 300
I know I can Blank() the amount if ISFILTERED() Location
But I'd like to show the amount (unshared) but keep the totals correct
Is there any way to do this in DAX
Thanks

I think what you need is something like this:
DEFINE MEASURE 'Fact'[RealAmount] =
IF (
COUNTROWS ( VALUES ( Fact[Location] ) ) = 1,
SUM ( Fact[Amount] ),
SUM ( Fact[Share_amount] )
)
It is not tested but should work, let me know if it works for you.

Here what i'm thinking - Can anyone comment if this will work or not:
DEFINE MEASURE 'Fact'[RealAmount] =
IF (
NOT (
ISFILTERED ( 'Fact'[Location])
)
,
SUM ( Fact[Amount] )
,
SUM ( Fact[Share_Amount] )
)

Related

Custom row cell in SQL

So I'm looking to use a custom row cell to label my data.
Basketball
Baseball
Golf
Cost
1
0
0
$50
0
1
0
$75
1
0
1
$150
0
1
1
$225
The table I have is above. What I'm trying to do is below:
OUTPUT:
Sport
Cost
Basketball
200
Baseball
300
Golf
375
I can get the sum of each sport but I'm having trouble making an alias for each sport on the output table (The first column)
How would I go about that? I've done an alias for a column header, but never for a row cell.
Thanks in advance!
select game
,sum(cost*flg) as cost
from t
cross join lateral (
values
(basketball, 'basketball')
,(baseball, 'baseball')
,(golf, 'golf')
) t2(flg, game)
group by game
game
cost
golf
375
baseball
300
basketball
200
Fiddle
Use a UNION with different WHERE conditions:
select sport, sum(cost)
from
(
select 'Basketball' as sport, cost
from the_table
where basketball = 1
union all
select 'Baseball', cost
from the_table
where baseball = 1
union all
select 'Golf', cost
from the_table
where golf = 1
) t
group by sport;

Calculate every participant's points, based on winners result in age group

The winner of the competition stage in the respective age group is the participant who made the distance fastest. Each participant in the respective group receives for each stage points. The points obtained are calculated by dividing the time of the group winner by the time of the participant and multiplied by 1000. The total score is calculated by the sum of the points of the 5 best stages.
I have participant data like this.
AgeGroup Start_Nr First_name Last_Name Distance_result
-------------------------------------------------------------
M30 5 John Lala 180
M35 1 Paul Baba 175
M35 6 Patric Ziza 192
M30 3 Peter Mikel 190
S30 2 Sandra Lilua 250
S30 4 Julia Parker 260
And I want to calculate and display point like this
Age_Group|Start_Nr|First_name|Last_Name|Distance_result|Points
----------------------------------------------------------
M30 5 John Lala 180 1000
M30 3 Peter Mikel 190 947
M35 6 Patric Ziza 175 1000
M35 1 Paul Babas 185 946
S30 2 Sandra Lilua 250 1000
S30 4 Julia Parker 260 962
Each winner in age group gets 1000points, others in that age group get points calculating -> (MIN(Distance_result)/(Distance_result) * 1000)
SELECT [Age_group],
[Start_number] ,
[First_name],
[Last_name],
[Stage_Nr],
[Distance_result], (180/[Distance_result]*1000) AS Points,
DENSE_RANK() OVER (PARTITION BY [Age_group] ORDER BY [Distance_result] ASC) AS PlaceRank
FROM [ParticipantDetails].[dbo].[ParticipantForm]
How can I use MIN(Distance_result) in each age group to do point calculations?
In my solution I can calculate points only inserting MIN(Distance_result) manually, but even then it's not correct to other age groups. In every age group there is a different best result.
In my Example I have solved your problem with a subquery.
I have also added round to remove the decimals and before that I have added cast to get some result, otherwise I would receive only 1 or 0, or you can do this: p1.[Distance_result] instead of cast...
SELECT [AgeGroup],
[Start_Nr] ,
[First_name],
[Last_name],
[Distance_result],
(select round(min(p2.Distance_result)/p1.[Distance_result] * 1000, 0) AS Points
from ParticipantForm p2
where p2.AgeGroup = p1.AgeGroup
group by p2.AgeGroup) as Points,
DENSE_RANK() OVER (PARTITION BY [AgeGroup] ORDER BY [Distance_result] ASC) AS PlaceRank
FROM [ParticipantForm] p1
Here you can see the demo.
You can use a sub-query to get the best times and join the table to it.
From a performance point of view it is preferable to have a sub-query in the join which is run only once than a row-level sub-query which is run for every line.
We avoid the need to cast as float and use round() by doing the multiplication by 1000 before the division.
SELECT
[Age_group],
[Start_number] ,
[First_name],
[Last_name],
[Stage_Nr],
[Distance_result],
(b.best*1000)/[Distance_result AS Points,
DENSE_RANK() OVER (PARTITION BY [Age_group] ORDER BY [Distance_result] ASC) AS PlaceRank
FROM [ParticipantDetails].[dbo].[ParticipantForm]
JOIN ( SELECT [Age_group] AgeGroup,
MIN([Distance_result]) AS best
FROM [ParticipantDetails].[dbo].[ParticipantForm]
GROUP BY [Age_group]) AS b
ON b.[AgeGroup] = [ParticipantForm].[Age_group];
Try calculating the minimum Distance_Result partitioned by Age_Group. Then calculate the points.
WITH cte AS (
SELECT *
, DENSE_RANK() OVER (PARTITION BY [Age_Group] ORDER BY [Distance_Result] ASC) AS Place_Rank
, MIN(Distance_Result) OVER (PARTITION BY [Age_Group] ORDER BY [Distance_Result] ASC) AS Min_Distance
FROM [ParticipantForm]
)
SELECT [Age_group]
, [First_Name]
, [Last_Name]
, [Start_Number]
, [Distance_Result]
, CAST(ROUND( [Min_Distance] * 1000.0 / [Distance_Result], 0 ) AS INT) AS Points
FROM cte
Results:
Age_group
First_Name
Last_Name
Start_Number
Distance_Result
Points
M30
John
Lala
5
180
1000
M30
Peter
Mikel
3
190
947
M35
Paul
Baba
1
175
1000
M35
Patric
Ziza
6
192
911
S30
Sandra
Lilua
2
250
1000
S30
Julia
Parker
4
260
962
db<>fiddle here

How to Select ID's in SQL (Databricks) in which at least 2 items from a list are present

I'm working with patient-level data in Azure Databricks and I'm trying to build out a cohort of patients that have at least 2 diagnoses from a list of specific diagnosis codes. This is essentially what the table looks like:
CLAIM_ID | PTNT_ID | ICD_CD | DATE
---------+---------+--------+------------
1 101 2500 01_25_2020
2 101 3850 03_13_2018
3 222 2500 10_26_2018
4 222 8888 11_30_2018
5 222 9155 04_01_2019
6 871 2500 02_17_2020
7 871 3200 09_09_2019
The list of ICD_CD codes of interest is something like [2500, 3850, 8888]. In this case, I would want to return TOTAL UNIQUE PTNT_ID = 2. These would be PTNT_ID = (101, 222) as these are the only two patients that have at least 2 ICD_CD codes of interest.
When I use something like this, I'm able to return all of the relevant PTNT_ID values, but I'm not able to get the total count of these PTNT_ID:
select mc.PTNT_ID
from MEDICAL_CLAIMS mc
where mc.PTNT_ID in ( # list of ICD_CD of interest
)
group by mc.PTNT_ID
having count(distinct mc.PTNT) >= 2
When I try to add a COUNT statement in, it returns an error
Just select from the query:
select count(*)
from
(
select mc.PTNT_ID
from MEDICAL_CLAIMS mc
where mc.PTNT_ID in ( # list of ICD_CD of interest )
group by mc.PTNT_ID
having count(distinct mc.PTNT) >= 2
) ptnts;

Distinct SUM in recursive tablix

I need to report the sum of sales by user and include recursive totals. The problem is, each account has 2 account managers, and the account managers can come from different teams. At each parent level, I want return the distinct sum of each relevant account at the group level.
For example:
Name LEVEL AccountNum Sales
James 1 A1 1000
A2 2000
A3 5000
Mike 2 A1 1000
A2 2000
Sally 3 A1 1000
John 3 A1 1000
Mary 3 A2 2000
Matt 2 A2 2000
A3 5000
Andy 3 A2 2000
A3 5000
Bob 3 A3 5000
I want to return the totals only and not show the account details:
Name Sales
James 8000
Mike 3000
Sally 1000
John 1000
Mary 2000
Matt 7000
Andy 7000
Bob 5000
I'm a relative newbie to SSRS, so would massively appreciate any advice on how to achieve the above group totals! Thanks!
I tried using recursive queries in SQL, but the totals only work up to Level 2, because of the cross-team accounts. Using partition by ranking also only works up to Level 2. (e.g.
{row_number() over (partition by AccountNum, TeamLeaderKey ORDER BY AccountNum ASC))}) in order to exclude any with rank > 1. This falls down at level 1 when there are account with account managers from different teams at level 2.
In case anyone else ever comes across this problem, this is how I solved it. I introduced two new fields in my dataset:
IntraTeamRank:
Case When ROW_NUMBER() OVER (PARTITION BY AccountNum, TeamLeaderKey ORDER BY AccountNum ASC) > 1 Then 0 Else 1 End
InterTeamRank:
Case When ROW_NUMBER() OVER (PARTITION BY AccountNum ORDER BY AccountNum ASC) > 1 Then 0 Else 1 End
I have a parameter set up in SSRS to return the max level.
I then used the following expression in SSRS:
IIf( Level() < (Parameters!MaxLevel.Value - 1),
SUM((Fields!InterTeamRank.Value * Fields!Amount.Value), "StaffName", Recursive),
IIf( Level() = (Parameters!MaxLevel.Value - 1),
SUM((Fields!IntraTeamRank.Value * Fields!Amount.Value), "StaffName", Recursive),
SUM(Fields!Amount.Value), "StaffName")
)
)
Maybe not the most elegant solution, but it worked for my purposes. It would break if an account were shared between regions, as opposed to just teams, but it is unlikely in my scenario. I'd still be interested to know if anyone has a more robust solution.

How to insert multiple columns value under a single column and separate the column name?

In the database there is a table
Name | id | Yearly_Profit | Yearly_Loss | Monthly_Profit | Monthly_loss
Alex 1 10 20 30 40
Ben 2 100 200 300 400
The output table will be like this
Name | id | Profit | Loss | Type
Alex 1 10 20 Yearly
Ben 2 100 200 Yearly
Alex 1 30 40 Monthly
Ben 2 300 400 Monthly
How can I do this?
Is this something like pivot or other?
You could use unpivot, but union all would be the simplest solution for you.
select Name, id, Yearly_Profit as Profit, Yearly_Loss as Loss, 'Yearly' as Type
from your_table
union all
select Name, id, Monthly_Profit , Monthly_loss, 'Monthly'
from your_table
This query would work for you, in this specific scenario.
SELECT
Name,
ID,
Yearly_Profit AS 'Profit',
Yearly_Loss AS 'Loss',
'Yearly' AS 'Type'
FROM Table
UNION ALL
SELECT
Name,
ID,
Monthly_Profit AS 'Profit',
Monthly_Loss AS 'Loss',
'Monthly' AS 'Type'
FROM Table
ORDER BY 5
But, if you'd have multiple columns in your table then you'd probably have to use a UNPIVOT.