I have a piece of a report which currently works fine with hard-coded years, I am trying to make them a bit more dynamic so as to show the current year and previous year returns to avoid having to update this every year. This is a simple thing to do in SQL, but I'm having a much harder time figuring this out in MDX, which I am still learning. The row in question is the [Date].[Year].&[2013]:[Date].[Year].&[2014]. Here is my current query:
SELECT {
[Measures].[Users],
[Measures].[Sessions]
} ON COLUMNS,
(
{[User Type].[Description].&[Customer], [User Type].[Description].&[Vendor]},
[Date].[Year Month].[Year Month],
[Date].[Month Name].[Month Name],
[Date].[Year].&[2013]:[Date].[Year].&[2014]
) ON ROWS
FROM [My Cube]
Thanks for any help.
You can't use a range inside a tuple. You first need to create a member.
Put this in before the SELECT clause:
WITH Member [Date].[Periods] as Aggregate( [Date].[Year].&[2013]:[Date].[Year].&[2014])
and then replace the range in your tuple by [Date].[Periods]
Related
I am trying to get a total summation of both the ItemDetail.Quantity column and ItemDetail.NetPrice column. For sake of example, let's say the quantity that is listed is for each individual item is 5, 2, and 4 respectively. I am wondering if there is a way to display quantity as 11 for one single ItemGroup.ItemGroupName
The query I am using is listed below
select Location.LocationName, ItemDetail.DOB, SUM (ItemDetail.Quantity) as "Quantity",
ItemGroup.ItemGroupName, SUM (ItemDetail.NetPrice)
from ItemDetail
Join ItemGroupMember
on ItemDetail.ItemID = ItemGroupMember.ItemID
Join ItemGroup
on ItemGroupMember.ItemGroupID = ItemGroup.ItemGroupID
Join Location
on ItemDetail.LocationID = Location.LocationID
Inner Join Item
on ItemDetail.ItemID = Item.ItemID
where ItemGroup.ItemGroupID = '78' and DOB = '11/20/2019'
GROUP BY Location.LocationName, ItemDetail.DOB, Item.ItemName,
ItemDetail.NetPrice, ItemGroup.ItemGroupName
If you are using SQL Server 2012 , you can use the summation on partition to display the
details and aggregates in the same query.
SUM(SalesYTD) OVER (ORDER BY DATEPART(yy,ModifiedDate)),1)
Link :
https://learn.microsoft.com/en-us/sql/t-sql/functions/sum-transact-sql?view=sql-server-ver15
We can't be certain without seeing sample data. But I suspect you need to remove some fields from you GROUP BY clause -- probably Item.ItemName and ItemDetail.NetPrice.
Generally, you won't GROUP BY a column that you are applying an aggregate function to in the SELECT -- as in SUM(ItemDetail.NetPrice). And it is not very common, in my experience, to GROUP BY columns that aren't included in the SELECT list - as you are doing with Item.ItemName.
I think you need to go back to basics and read about what GROUP BY does.
First of all welcome to the overflow...
Second: The answer is going to be "It depends"
Any time you aggregate data you will need to Group by the other fields in the query, and you have that in the query. The gotcha is what happens when data is spread across multiple locations.
My suggestion is to rethink your problem and see if you really need these other fields in the query. This will depend on what the person using the data really wants to know.
Do they need to know how many of item X there are, or do they really need to know that item X is spread out over three sites?
You might find you are better off with two smaller queries.
I would like to report the state of data availability resp. the max date specific measure(groups) have data loaded. This is a functionality I would then try to incorporate into each report. In theory each measure could have another "last member with data" in the date dimension however it is OK for the moment to simplify that to one measure per measure group or the max for the whole measure group.
I have written an MDX query which gives me the relevant answer. However to leverage easier maintenance I am striving to incorporate that information as a calculated member into the cube itself. Using MDX only every leap year or so I did not successfully manage to convert the query into a calculated member definition.
// Repro-Query on Adventure Works
// with Adventure Works 2012 EE result should be "July 31, 2008"
// contrasted to last date in date dimension which is "December 31,2010
WITH Member [Measures].[Data Availability] AS
[Date].[Calendar].CurrentMember.Name
SELECT
{
[Measures].[Data Availability]
} ON COLUMNS
FROM
[Adventure Works]
WHERE
{
TAIL(
FILTER
(
[Date].[Date].Members,
[Measures].[Internet Sales Amount] >0
)
,1
)
}
Result shoud be the same as in the query but encapsulated within one calculated measure statement. Remember I don't need the value of the measure but just the name of the last dimension element with data in the date dimension.
Regarding code it should be something like this:
WITH Member [Measures].[Data Availability] AS
<your great translation to a member >
SELECT
{
[Measures].[Data Availability]
} ON COLUMNS
FROM
[Adventure Works]
Feel free to suggest different approaches to get the answer to the problem like better performing ways to calculate the last member with data.
Thanks for the great question and for using Adventure Works. Despite what some commenters say, that’s a great way to get an answer here.
Try this. The Tail function returns a set so .Item(0).Item(0) turns it into a member by choosing the first tuple and first member.
WITH Member [Measures].[Data Availability] AS
TAIL(
FILTER
(
[Date].[Date].Members,
[Measures].[Internet Sales Amount] >0
)
,1
).Item(0).Item(0).Name
SELECT
{
[Measures].[Data Availability]
} ON COLUMNS
FROM
[Adventure Works]
UPDATED screenshot after attempting #Dude_Scott's suggestion:
Desired output of data is in the blue table.
Our data includes users who have registered between 1989-2016.
All have registered at least once.
Some register every year and some skip years.
Our question is for each year, find how many years previous users registered.
We want results to be 0yr, 1yr, 2yr, 3yr, etc., for each year.
Arrays are working correctly.
I've organized the data structure in Excel this way:
1) UserID All Years
For year 1989, result is 0, since it was the first year of data collection.
For year 1990, this formula returns the expected count:
=COUNT(IF($B$2:$B$11613=1989,1/COUNTIFS($A$2:$A$11613,$A$2:$A$11613,$B$2:$B$11613,1989)))
Beginning with year 1991 is where I am tripped up: I can't find for multiple years.
This formula is not working:
=COUNT(IF(AND(OR($B$2:$B$11613=1989,1990,1/COUNTIFS($A$2:$A$11613,$A$2:$A$11613,$B$2:$B$11613,1989,1990)))))
Where do I argue "COUNTIF 0 yr, 1 yr, 2 yr", etc. Thanks in advance. --f66
Since your using COUNTIF, I'm assuming you can use SUMPRODUCT also. In the below screen shot I am using this formula
=SUMPRODUCT(($A$2:$A$11=$D3)*($B$2:$B$11<=F$2))&" yr"
Without a sample of the workbook its a little difficult to determine what the output of your data should look like, but give it a go.
Side note, I would suggest updating the User ID and Years into a table format and giving it a named range, so you don't iterate though tens of thousands of lines with the array formula.
I may be reading this all wrong, but this seems to be a straightforward use case for a pivot table!
Select your data range
Set USERID as your row headings
Set YEARS as your column headings
Set count of USERID as your values
I do not use excel anymore, but below is a link to output for doing this with test data on google sheets.
I am trying to get the data fromt the present calender week to the previous two weeks. If I specify the date range as parameters in the MDX query, the table gets filled up properly.
SELECT NON EMPTY {[Measures].[planned_cumulative],[Measures].[Last Forecast CW] } ON COLUMNS,
NON EMPTY { ([Project].[Projekt-Task].[Task].ALLMEMBERS* { [Date].[Date - CW].[Week].&[2014]&[201420] : [Date].[Date - CW].[Week].&[2014]&[201422]})} ON ROWS FROM [DWH]
But if I try and use the lag function, I get an error. Here is the MDX query.
SELECT NON EMPTY {[Measures].[planned_cumulative],[Measures].[Last Forecast CW] } ON COLUMNS,
NON EMPTY { ([Project].[Projekt-Task].[Task].ALLMEMBERS* [Date].[DATECW - CW].[Week].CurrentMember.Lag(2) ) } ON ROWS
FROM [DWH]
Your first query (quite rightly) identifies a range of two weeks, by using two members from the dimension separated by a colon i.e. [Week X] : [Week Y].
Your second query uses the LAG function, which will return a member on your dimension, not a range of members.
Try this:
SELECT NON EMPTY {[Measures].[planned_cumulative],[Measures].[Last Forecast CW] } ON COLUMNS,
NON EMPTY {[Project].[Projekt-Task].[Task].ALLMEMBERS * TAIL([Date].[Date - CW].[Week],3) } ON ROWS
FROM [DWH]
Also, your first query refers to [Date].[Date - CW].[Week] whereas your second query uses [Date].[DATECW - CW].[Week]. I have gone with the first option as you say that query works.
Let me know if that helps.
Ash
EDIT: Apologies for that. I have amended the query to use the TAIL function, which will give you a number of tuples from a set starting at the end and working backwards. So with TAIL ({Set Of Weeks},3) this should give you the current week and the previous two weeks. I have tested a similar query on my cube and it seems produce the expected results.
Hope that solves it for you.
Ash
I'm currently working my way through the exam study book, Querying Microsoft SQL Server 2012. I've been learning SQL over the last few months and I am currently looking over windowing functions. I came to this application question and it got me thinking about another question, which I'll list below:
So in the columns diffprev and diffnext it only lists the difference between the previous and the next value. How could I list the maximum difference between subsequent values across all of the rows (partitioned by custid)? So just scanning the table, I see that in custid 1's history, the greatest difference between subsequent rows is $548. Then for custid 2, the greatest difference is $390.95. I could see these values appearing in a maxdiff column across all the rows pertaining to the partition.
Thank you for aiding my studying!
If you're just looking for the value, this should work:
with cte as (
select custid, val - lag(val)
over (partition by custid order by orderdate, orderid) as prevVal
from Sales.OrderValues
)
select custid, max(abs(val))
from cte
group by custid
If you want the details of the rows that attain that maximum, it'll be a bit more work.
Bonus tip - pictures of text are the worst. You're more likely to get help if the people helping don't need to type your code out. Even better though would be a fully functioning example (complete with table definitions and sample data) so we can verify against your data!