MDX Calculation on SETS - set

I have an MDX query where I am using a Parent-Child hierarchy where a property on any level have a specific values.
Now I want to take create a sets, that have each of these specific values and subtract them from each other
The query I have looks like this:
WITH
SET [OMS] AS
{
DESCENDANTS(
FILTER([ReportHierarchy].[Hierarchy].MEMBERS,
[ReportHierarchy].[Hierarchy].Properties( "Sum Code" )="OMS")
,,SELF)
}
SET [VF] as {
DESCENDANTS(
FILTER([ReportHierarchy].[Hierarchy].MEMBERS,
[ReportHierarchy].[Hierarchy].Properties( "Sum Code" )="VF")
,,SELF)
}
SELECT
{
[Measures].[Amount],
[Measures].[Budget Amount]
} ON COLUMNS,
{
[OMS],
[VF]
}
on ROWS
FROM
Finance
WHERE
[ReportHierarchy].[Hierarchy Name].&[Income and Balance]
which returns this result:
Amount Budget Amount
Nettoomsætning -126418831.1 -308192540.75
Vareforbrug 65415924.25 159307880.45
Now I want to do a calulation which subtracts SET [VF] from set [OMS]...
Anyone have any suggestions?

you need WITH MEMBER to create a new item in your left-most column. This new item can be set up to calculate the value of one item minus another. Here's a similar situation from an old query I wrote years ago:
WITH MEMBER [Actual Time].[MySubtraction]
AS '[Actual Time].[Week].[Week 5] - [Actual Time].[Week].[Week 4]', SOLVE_ORDER=80
SELECT {
[Location].[All Location].[Blah Blah]
} ON ROWS,{
[Actual Time].[Week].members,
[Actual Time].[MySubtraction]
}
ON COLUMNS FROM [CubeName]
WHERE ([Measures].[Whatever])
My MDX is getting rusty these days, so I have not tried to give you the exact query you need, sorry. Have a look at the documentation for WITH MEMBER to learn more.

Related

MDX: add dimension in filter but also show in rows

I have a simple MDX query that filters data to one of two Status values:
SELECT
NON EMPTY
{ [confidentialstring].Members }
ON COLUMNS,
NON EMPTY
{ [APMWORDER].[LEVEL01].Members *
[APMSTDOPR].[LEVEL01].Members *
[AWOUSTAT].[LEVEL01].Members *
[ANOTIFCTN].[LEVEL01].Members
}
ON ROWS
FROM [APM_CP002/APM_CP002_QX006]
WHERE { ( [AWOUSTAT].[E0001] ), ( [AWOUSTAT].[E0002] ) }
But I also need [AWOUSTAT] in my table, to see which status value is actually applicable.
However MDX throws an error if I add it: 'You may not use the same dimension on different axes'. I understand this in principle but not in this application ('filter' is not an axis to me...)
How can I resolve this, without having to create two queries?
Thanx!
Since you cannot have the same dimension on rows and in where clause, and you want to see [AWOUSTAT].[E0001]] , [AWOUSTAT].[E0002] , in your table, I think you could try something like this to start:
SELECT
NON EMPTY
{ [confidentialstring].Members }
ON COLUMNS,
NON EMPTY
{ ( [AWOUSTAT].[E0001]] ), ( [AWOUSTAT].[E0002] ) }
ON ROWS
FROM [APM_CP002/APM_CP002_QX006]
A common technique is to replace the WHERE clause with a FROM clause.
Sample using adventure works:
SELECT
NON EMPTY
{[Measures].[Order Count]} ON COLUMNS
,NON EMPTY
{[Date].[Day of Month].[Day of Month].ALLMEMBERS}
ON ROWS
FROM
(
SELECT
{[Date].[Fiscal Year].&[2011]} ON COLUMNS
FROM [Adventure Works]
)
In the above example, it is equivalent to having a WHERE clause of the Fiscal Year = 2011.
You can see a similar output, whenever you use the SSMS Cube Browser to build queries.
It may look strange to replace WHERE with FROM, BUT, in the in most cases with the Cube, it does provide the required output.

Which way will get high performance while selecting many data IQueryable Vs For loop (Using Entity Frame Work)

I am trying to get a list from the database containing two or more lists inside that list.(using .net core, entity framework).Assume I have two table call header and details table.
Header Table
Detail Table
And I want the result like this:
{
"data":[
{
"Country":"Singapore",
"Hospital_List":[
{
"Hospital_Name":"SG Host A"
},
{
"Hospital_Name":"SG Host A"
}
]
},
{
}
]
}
I only know two ways to get the result like this,First Way, select Country list data with blank Hospital list as List,then for loop that list to select related Hospital list from db again.
And Second Way,select Country list data with blank Hospital list as IQueryable List,and then select related Hospital list via jointing with Hospital Table.So my question is
Which way should i used to get higher performance? And Is any other way?
Please remember there has a lot of field and data in my real table.
For loop give give you the lowest perfomance, because you will create SQL query for each iteration. Instead of this, try following solution:
from hospital in hospitals
group hospital by hospital.CID into gh
join country in countries
on gh.FirstOrDefault().CID equals country.CID
select new
{
Country = country.Country,
Hospital_List = from h in gh select h
}
EDITED:
And if your model created right you can use this code:
from hospital in hospitals
join country in countries
on hospital.Country equals country
group hospital by hospital.CID into gh
select new
{
Country = from h in gh select h.Country.Country,
Hospital_List = from h in gh select h
}

Laravel Eloquent: Count Rows and group them by the day

I have a Model called "AdInteraction", these interactions can either be a click or a view (They either have boolean clicked or boolean viewed set to true).
Along every Interaction I save the created_at date.
Now this is what I want to end up with in order to have all the data I need to populate a ChartJS Chart:
[
{
"date": "01-01-2018"
"clicks": 13,
"views": 25
},
{
"date": "02-01-2018"
"clicks": 25,
"views": 74
},
{
"date": "03-01-2018"
"clicks": 0,
"views": 0
},
]
This is a query I already got on my Ad model which is related to AdInteraction:
public function getClicksForLastDays()
{
return $this->clicks()->get()->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('y-m-d');
});
}
However this returns me an array of arrays looking like this:
What would be the correct and most efficient way to fetch the clicks and count them by days?
try this and let me know, I assume your column names are date,clicks,views, if its different then pls let me know, so I will adjust the answer or you can do it your self..
AdInteraction::select([DB::raw('DATE(date)'),DB::raw('count(case when clicks ="true" then 1 end) as "Clicks"'),
DB::raw('count(case when views ="true" then 1 end) as "Views"')])
->groupBy(DB::raw('DATE(date)'))
->get();
or try this
AdInteraction::select([DB::raw('DATE(date)'),DB::raw('count(case when clicks =true then 1 end) as "Clicks"'),
DB::raw('count(case when views =true then 1 end) as "Views"')])
->groupBy(DB::raw('DATE(date)'))
->get();
You should consider abandoning the idea of grouping by date using datetime column since such query will be very inefficient. When you, for example, GROUP BY DATE(created_at) MySQL will be performing this cast function for each row and won't be able to utilize indexes for created_at.
Therefore I recommend you to denormalize your table by introducing separate DATE created_date_at column for created_at value and create an index for it. Then you will be able to efficiently group your stats by this new column value. Just be sure to register the following code for your model:
AdInteraction::creating(function ($adInteraction) {
$adInteraction->created_date_at = $adInteraction->created_at->format('Y-m-d');
});
Or you can consider creating separate int columns for year, month and day. Then you can create a multi-column index and group by these columns. This way you will be able to also easily retrieve stats by days, months and years if needed.

Get first record of each entity order by a column

I have a query in linq that fetch students assessments data something like
new {x.StudentId, x.StudentAssessmentId, x.AssessmentName, x.SubmittedDate}
then I perform some operations on this list to get only last added student assessment per student, I get last studentassessment by finding the max id of studentassessment,
so I finally get last studentassessments data of all the students.
Is there a way to do this directly in the initial list?
I thought about the way to group the results by student Id and select max of studentassessmentid, like
group x.StudentAssessmentId by x.StudentId
select new {x.Key, x.Max()}
in this way I will get student with there last studentassessmentid which is what I want but this will only give me studentassessment ids while I want other data also like AssessmentName, SubmittedDate etc.
Try something like this:
group x.StudentAssessmentId
by new {
x.StudentId,
x.AssessmentName,
x.SubmittedDate }
into g
select new
{
g.Key.StudentId,
g.Key.AssessmentName,
g.Key.SubmittedDate,
g.Max(),
}

SOQL - single row per each group

I have the following SOQL query to display List of ABCs in my Page block table.
Public List<ABC__c> getABC(){
List<ABC__c> ListABC = [Select WB1__c, WB2__c, WB3__c, Number, tentative__c, Actual__c, PrepTime__c, Forecast__c from ABC__c ORDER BY WB3__c];
return ListABC;
}
As you can see in the above image, WB3 has number of records for A, B and C. But I want to display only 1 record for each WB3 group based on Actual__c. Only latest Actual__c must be displayed for each WB3 Group.
i.e., Ideally I want to display only 3 rows(one each for A,B,C) in this example.
For this, I have used GROUPBY and displayed the result using AggregateResults. Here is the result.
I got the Latest Actual Date for each WB3 as shown above. But the Tentative date is not corresponding to it. The Tentative Date is also the MAX in the list.
Here is the code I used
public List<SiteMonitoringOverview> getSPM(){
AggregateResult[] AgR = [Select WB_3__c, MAX(Tentaive_Date__c) dtTentativeDate , MAX(Actual_Date__c) LatestCDate FROM Site_progress_Monitoring__c GROUP BY WBS_3__c];
if(AgR.size()>0){
for(AggregateResult SalesList : AgR){
CustSumList.add(new SiteMonitoringOverview(String.ValueOf(SalesList.ge​t('WB_3__c')), String.valueOf(SalesList.get('dtTentativeDate')), String.valueOF(SalesList.get('LatestCDate')) ));
}
}
return CustSumList;
}
I am forced to use MAX() for tentative date. I want the corresponding Tentative date of the MAX Actual Date. Not the Max Tentative Date.
For group A, the Tentative Date of Max Actual Date is 12/09/2012. But it is displaying the MAX tentative date: 27/02/2013. It should display 12/09/2012. This is because I am using MAX(Tentative_Date__c) in my code. Every column in the SOQL query must be either GROUPED or AGGREGATED. That's weird.
How do I get the required 3 rows in this example?
Any suggestions? Any different approach (looping within in groups)? how?
Just ran into this issue myself. The solution I came up with only works if you want the oldest or newest record from each grouping. Unfortunately it probably won't work in your case. I'll still leave this here incase it does happen to help someone searching for a solution to this issue.
AggregateResult[] groupedResults = [Select Max(Id), WBS_3__c FROM Site_progress_Monitoring__c GROUP BY WBS_3__c];
Calling MAX or MIN on the Id will let you get 1 record per group condition. You can then query other information. I my case I just need 1 record from each group and didn't really care which one it was.

Resources