Please consider this structure:
Fact:
Sender Receiver Amount
----------------------------------------
Reseller1 Resseler2 100
Reseller1 Resseler3 200
Reseller3 Resseler1 150
Reseller3 Resseler2 50
Reseller1 Resseler4 100
Reseller4 Resseler2 350
Reseller4 Resseler1 500
Reseller4 Resseler3 250
DimReseller:
ResellerCode ResellerName
---------------------------------------
1 Reseller1
2 Reseller2
3 Reseller3
4 Reseller4
DimReseller is role-playing dimension and has 2 relation with fact table:
Now I wrote this MDX query to select How much money the resellers have paid each other:
WITH MEMBER SenderAmount AS
[Measures].[Amount], FORMAT_STRING = "Standard"
SELECT {SenderAmount} ON 0,
NON EMPTY [Sender].[Hierarchy].MEMBERS ON 1
FROM [MyCube]
and I get this result:
Now I want to get how much money the resellers have received from each other and I wrote this query:
WITH
MEMBER SenderAmount AS
[Measures].[Amount], FORMAT_STRING = "Standard"
MEMBER ReceiverAmount AS
(LinkMember
([Sender].[Hierarchy].CurrentMember, [Receiver].[Hierarchy])
,[Measures].[Amount]), FORMAT_STRING = "Standard"
SELECT {SenderAmount, ReceiverAmount} ON 0,
NON EMPTY [Sender].[Hierarchy].MEMBERS ON 1
FROM [MyCube]
and get this result:
I got null for receive amount. I test this MDX query:
select {LinkMember([Sender].[Hierarchy].[Reseller Code].&[1], [Receiver].[Hierarchy])} on 0
from [MyCube]
and I get 650 (the correct amount) for Reseller1 .Now when I change the query this way:
select {LinkMember([Sender].[Hierarchy].currentmember, [Receiver].[Hierarchy])} on 0,
[sender].[Hierarchy].members on 1
from [MyCube]
I get this result(Again for paid):
and when I change the query this way:
select {LinkMember([Sender].[Hierarchy].currentmember, [Receiver].[Hierarchy])} on 0,
[receiver].[Hierarchy].members on 1
from [MyCube]
I got this error:
The Hierarchy hierarchy already appears in the Axis0 axis.
How can I get this result?
Reseller Received Paind
--------------------------------------------------------
Reseller1 650 400
Reseller2 500 (null)
Reseller3 450 200
Reseller4 100 1100
Sorry for too much explanation...
Thanks
Try the following change:
MEMBER ReceiverAmount AS
(LinkMember
([Sender].[Hierarchy].CurrentMember, [Receiver].[Hierarchy])
,[Measures].[Amount]
,[Sender].[Hierarchy].[All]), FORMAT_STRING = "Standard"
Related
I'm new to SQL, and I'm trying to create a database to manage a small inventory. This is the structure of the db:
DatabaseStructure
I need to create a query that returns the total inventory per material. So, the first step would be to look up for all the batches associated with the material. Second, look up for all the movements associated with each batch. Then, sum the quantity associated with each movement, but depending on the movement type (If it is a good receipt is addition (+), but if it is an inventory withdrawal is subtraction (-)).
Here is an example of the tables with sample data and the desired result.
Table Material
MaterialID
MaterialDescription
1
Bottle
2
Box
Table Batch
BatchID
MaterialID
VendorMaterial
VendorBatch
ExpirationDate
1000
1
2096027
00123456
12/12/2025
1001
1
2096027
00987654
11/11/2026
1002
2
102400
202400E
10/10/2023
Table Movement
MovementID
BatchID
MovementType
Quantity
CreatedBy
CreatedOnDate
1
1000
Good receipt
100
user1#email.com
4/10/2022
2
1000
Inventory withdrawal
20
user2#email.com
4/15/2022
3
1000
Inventory withdrawal
25
user3#email.com
4/17/2022
4
1001
Good receipt
100
user1#email.com
4/20/2022
5
1001
Inventory withdrawal
10
user4#email.com
4/26/2022
6
1002
Good receipt
50
user1#email.com
2/26/2022
Expected query result - total inventory per material:
MaterialDescription
TotalInventory
Bottle
145
Box
50
TotalInventory calculation: for Bottle there are two good receipts movements of 100 and three withdrawals of 20, 25 and 10. So, total inventory will be (100+100)-(20+25+10)=145.
Thanks for your help!
select
mat.MaterialDescription,
sum(
case mov.MovementType
when 'Good receipt' then 1
when 'Inventory withdrawal' then -1
else 0 /* don't know what to do for other MovementTypes */
end * mov.Quantity
) as TotalInventory
from
Material as mat
left join Batch as bat on bat.MaterialID = mat.MaterialID
left join Movement as mov on mov.BatchID = bat.BatchID
group by
mat.MaterialDescription
;
I have a simplified example cube used for learning purposes, and to try to figure out a more complex problem.
The cube represents a small web server log,
number of hits as a measure
hostname as a dimension
http status code as a dimension
I can get a breakdown on number of hits per host and http status code with the MDX
SELECT NON EMPTY { [Measures].[CNT HITS] } ON COLUMNS,
NON EMPTY { ([DIM NOS STATUSCODE].[Statuscode].[Statuscode].ALLMEMBERS *
[DIM NOS HOST].[HOST].[HOST].ALLMEMBERS ) } ON ROWS
FROM [DW]
Now what I would like is to make groups over various HTTP status codes to e.g. show the percentage of successful hits (all 2xx status codes), the percentage unsuccessful hits (all non 2xx status codes).
I can do this with SQL, but I'm at a loss on how to do it with MDX. e.g. with SQL I'd do:
select HOST,
sum(CNT_HITS) as HITS ,
SUM(CASE WHEN s.statuscode div 100 = 2 THEN CNT_HITS ELSE 0 END)/sum(CNT_HITS) * 100 as success_percent,
SUM(CASE WHEN s.statuscode div 100 = 2 THEN 0 ELSE CNT_HITS END)/sum(CNT_HITS) * 100 as failed_percent,
sum(CASE WHEN s.statuscode = 401 THEN CNT_HITS ELSE 0 END)/sum(CNT_HITS) * 100 as auth_fail_percent
from FACT_NOS_HTTPLOG fact
group by HOST;
And for the data shown in the above screenshot, I'd get
+-----------------+------+-----------------+----------------+-------------------+
| HOST | HITS | success_percent | failed_percent | auth_fail_percent |
+-----------------+------+-----------------+----------------+-------------------+
| www.example.com | 1610 | 93.1677 | 6.8323 | 6.2112 |
| www.test.com | 50 | 0.0000 | 100.0000 | 0.0000 |
+-----------------+------+-----------------+----------------+-------------------+
But how can I accomplish this with MDX ?
I think the easiest way to accomplish this is to add a column to your fact table (or view/query) that would contain keys for either success_percent, failed_percent or auth_fail_percent. Then create a new dimension with these 3 members. Join to the fact and you have your solution without the need for any MDX at all.
Add an extra attribute [Status] to your [DIM NOS STATUSCODE] dimension and use MDX for percentage, like this:
([DIM NOS STATUSCODE].[Status].&[Failed],[Measures].[CNT HITS]) / [Measures].[CNT HITS]
It will involve a certain amount of hard coding - although you could add these measures into your cube script.
WITH
MEMBER [Measures].[failed_percent] AS
DIVIDE(
(
[DIM NOS STATUSCODE].[Status].&[Failed]
,[DIM NOS HOST].[HOST].currentmember
,[Measures].[CNT HITS]
)
, (
[DIM NOS STATUSCODE].[Status].[All]
,[DIM NOS HOST].[HOST].currentmember
,[Measures].[CNT HITS]
)
)
SELECT
NON EMPTY
{
[Measures].[CNT HITS]
,[Measures].[failed_percent]
} ON COLUMNS,
NON EMPTY
[DIM NOS HOST].[HOST].[HOST].ALLMEMBERS
ON ROWS
FROM [DW];
SSAS and MDX newbie here.
If I have an SSAS cube with Geography, Product as the dimensions and total sales as a measure.
The following elements are under geography:
EAST
WEST
NORTH
SOUTH
MID-ATLANTIC
MOUNTAIN
NORTH-WEST
Products are:
1
2
3
4
For Product ID = 1, is there a way I can group some members into a "rest of the country" bucket and aggregate the sales?
Meaning, the expected output is:
Product ID Geography Sales
1 East 100
1 West 200
1 North 300
1 South 400
1 RestOfNation 1200
2 East 100
2 West 50
2 RestOfNation 1500
Is there a way I can buck some members into "RestOfNation" using an MDX query?
You could try something like this.
Create a named set made up of the members that you'd like to throw into the bucket RestOfWorld.
Make a member, within the geography dimension, that is the aggregation of the rest of world members.
Find the countries that are not in the rest of the world set.
Here is a script against AdvWrks (worth installing as it is a common prototyping tool when playing with mdx and posting to forums):
WITH
SET [RestOfWorld] AS
{
[Customer].[Customer Geography].[Country].&[United Kingdom]
,[Customer].[Customer Geography].[Country].&[Germany]
}
MEMBER [Customer].[Customer Geography].[All].[RestOfWorld] AS
Aggregate
(
{
[Customer].[Customer Geography].[Country].&[United Kingdom]
,[Customer].[Customer Geography].[Country].&[Germany]
}
)
SET [CountriesMinusROW] AS
[Customer].[Customer Geography].[Country].MEMBERS - [RestOfWorld]
SELECT
NON EMPTY
{[Measures].[Internet Sales Amount]} ON 0
,NON EMPTY
[Product].[Category].[Category]
*
{
[CountriesMinusROW]
,[Customer].[Customer Geography].[All].[RestOfWorld]
} ON 1
FROM [Adventure Works]
WHERE
[Date].[Calendar Year].&[2007];
The above gives the following cellset:
I have an MDX/calculated member question here. It has been a while since I've done this and have forgotten a lot. I have a cube with the following dimensions and levels:
Sites
Site Name
Clients
Client Name
Industry Name
I have a measure
Product Count
What I want to show/return from an MDX query is the following:
Site | Prod Count | Avg Prod Count Across All Sites for Current Client | Avg Prod Count
Across All Sites in Current Client's Industry
Example Data:
Site | Prod Count | Avg 1 | Avg 2
Site 1 | 100 | 50 | 200
Site 2 | 125 | 50 | 200
Site 3 | 112 | 50 | 200
What I'm trying to figure out is how or if I can use 2 different calculated members to calculate the averages above.
The challenge is that the query has to be in the following format because I'm using a reporting tool and it is generating the MDX.
`SELECT
{
[Measures].[Product Count],
[Measures].[Calc Avg 1],
[Measures].[Calc Avg 2]
} ON COLUMNS,
{[Sites].[Site Name].[Site Name].Members} ON ROWS
FROM [Cube]
where ([Clients].[Client Name].&[Client A])`
So basically, my question is:
What would be the proper way to define the averages I'm looking for using calculated members?
Whenever I try it out I'm only able to calculate the average product count across all sites for the current client, but I'm not able to get the average across all sites in the current client's industry.
here's an example using adventure works to get you started. the calculated members will need to be ported to the MDX script to use with your tool. Here's the mapping:
City = "Client Site"
State = "Client"
Country = "Client Industry"
WITH
MEMBER Measures.ClientCitiesCount AS
Exists(
[Customer].[City].[City] // represents client sites
,[Customer].[State-Province].CurrentMember // represents client
).Count
MEMBER Measures.ClientCitiesSales AS
SUM(
[Customer].[State-Province].CurrentMember
,[Measures].[Internet Sales Amount]
)
MEMBER Measures.AvgAcrossClientCities AS
ClientCitiesSales/ClientCitiesCount
MEMBER Measures.IndustryCitiesCount AS
Exists(
[Customer].[City].[City] // represents industry sites
,Exists(
[Customer].[Country].[Country] // represents client's industry
,[Customer].[State-Province].CurrentMember // represents client
)
).Count
MEMBER Measures.IndustryCitiesSales AS
SUM(
Exists(
[Customer].[Country].[Country]
,[Customer].[State-Province].CurrentMember
)
,[Measures].[Internet Sales Amount]
)
MEMBER Measures.AvgAcrossIndustryCities AS
IndustryCitiesSales/IndustryCitiesCount
SELECT
{
[Measures].[Internet Sales Amount]
,ClientCitiesCount
,ClientCitiesSales
,AvgAcrossClientCities
,IndustryCitiesCount
,IndustryCitiesSales
,AvgAcrossIndustryCities
} ON 0,
{
[Customer].[City].[City] // represents client sites
} ON 1
FROM
[Adventure Works]
WHERE
[Customer].[State-Province].&[GA]&[US] // represents client
Don't forget to add in some edge-case handling (e.g. IIF the client has 0 "sites" in context) and consider using the "measuregroup" parameter in the EXISTS function.
Im having an issue with an MDX query, and I think it boils down to the order of precedence between calculating an aggregate and a calculated member.
Let me start with the underlying data, which revolves around a valuation (which has a date, and some other data such as a member type, a scheme - and crucially for this question; a loading factor) and an associated value.
The data
Valuation Table
Id | Valuation Date | Member Type | Scheme | Loading Factor
=============================================================
1 | 2010-01-01 | TypeA | Scheme X | 0.02
2 | 2010-01-01 | TypeB | Scheme X | 0.02
3 | 2010-01-01 | TypeA | Scheme Y | 0.02
4 | 2010-01-01 | TypeB | Scheme Y | 0.02
ValuationValue table
ValuationId | Value
====================
1 | 1000.0
2 | 2000.0
3 | 3000.0
4 | 4000.0
This, when loaded into a cube has a Valuation dimension with attributes MemberType, Scheme and date. And a cube with Measure group ValuationValue containing Value measure, and a Valuation measure group containing Loading Factor like so:
Cube
-Measure Groups
- Valuation
|_Loading Factor
- ValuationValue
|_Value
- Dimensions
- Valuation
|_MemberType
|_Scheme
|_Date
The question
Loading factor is used to load the Value, think of it like a tax, so 0.02 means "Loading amount is 2% of the value". When returning Value from a query, I need to also calculate the amount to load this value by. A typical query might look like
SELECT
{
[Measures].[Value]
} ON 0,
[Valuation].[Scheme] ON 1
FROM Cube
This would return 2 rows, and as you can see by comparing to the data above it correctly sums across memberType:
Scheme | Value
=================
Scheme X | 3000.0
Scheme Y | 7000.0
Now, if I try to calculate my loading factor in that query, all goes wrong - i'll demonstrate. Given the following query:
WITH MEMBER [Measures].[Loading Value]
AS
(
[Measures].[Value] * [Measures].[Loading Factor]
)
SELECT
{
[Measures].[Value] ,
[Measures].[Loading Value]
} ON 0,
[Valuation].[Scheme] ON 1
FROM Cube
I get the result
Scheme | Value | Loading Value
=================================
Scheme X | 3000.0 | 120.0
Scheme Y | 7000.0 | 280.0
Basically, what is happening is that it is suming my Loading Factor and then multiplying that by the Sum of my values(The first row above should be 1000 * 0.02 + 2000 * 0.02 = 60. Instead it's calculating 3000 * 0.04 = 120).
This is of course a contrived example, my actual structure is a bit more complex - but I think this demonstrates the problem. I was under the impression that the calculated member in the example above should occur on a row-by-row basis, instead of at the end of an aggration of my Value measure.
Thanks for any replies.
Your [Measures].[Loading Factor] - How is that set, is it a SUM?
Calculated members are generally done as per the rows returned if I remember - Unless you specify otherwise.
If you want an example, take a look at the currency conversion wizard output - This does something similar using the LEAVES command - You will need to do this in the MDX script as a SCOPE'd command though.
Given your description, the code could be something like:
CREATE MEMBER [Measures].[Loading Value] AS NULL
Scope( { [Measures].[Loading Value] } );
Scope( Leaves([Valuation]) );
This = [Measures].[Value] * [Measures].[Loading Factor]
Format_String(This) = "#,##0.00;-#,##0.00";
End Scope;
End Scope;
I'm not sure I follow your example completely, but you might try using SOLVE_ORDER and SCOPE_ISOLATION to manipulate the order of the calculations.
For example,
WITH
MEMBER [Measures].[Custom Calculation] AS
'([Measures].[Sales Count] - [Measures].[Unit Returns])',
SOLVE_ORDER = 65535, SCOPE_ISOLATION = CUBE
SELECT
{[Measures].[Custom Calculation]} ON COLUMNS,
NON EMPTY [Time].[YQMD].[Day].AllMembers ON ROWS
FROM [Waremart]
Thes one turned out ot be REALLY easy.
WITH MEMBER [Measures].[Loading Value]
AS
(
[Measures].[Value] * [Measures].[Loading Factor]
)
WITH MEMBER [Measures].[Total Loading Value]
AS
SUM (
EXISTING [Valuation].[Id].[Id],
[Measures].[Loading Value]
)
SELECT
{
[Measures].[Value] ,
[Measures].[Measures].[Total Loading Value]
} ON 0,
[Valuation].[Scheme] ON 1
FROM Cube