MDX Count over time (years - not within a year) - sql

I'd like to be able to rollup the count of commitments to a product over years -
The data for new commitments in each year looks like this:
Year | Count of new commitments | (What I'd like - count of new commitments to date)
1986 4 4
1987 22 26
1988 14 40
1989 1 41
I know that within a year you can do year to date, month to date etc, but I need to do it over multiple years.
the mdx that gives me the first 2 columns is (really simple - but I don't know where to go from here):
select [Measures].[Commitment Count] on 0
, [Date Dim].[CY Hierarchy].[Calendar Year] on 1
from [Cube]
Any help would be great

In MDX something along the line:
with member [x] as sum(
[Date Dim].[CY Hierarchy].[Calendar Year].members(0) : [Date Dim].[CY Hierarchy].currentMember,
[Measures].[Commitment Count]
)
select [x] on 0, [Date Dim].[CY Hierarchy].[Calendar Year] on 1 from [Cube]

Use a common table expression:
with sums (year,sumThisYear,cumulativeSum)
as (
select year
, sum(commitments) as sumThisYear
, sum(commitments) as cumulativeSum
from theTable
where year = (select min(year) from theTable)
group by year
union all
select child.year
, sum(child.commitments) as sumThisYear
, sum(child.commitments) + parent.cumulativeSum as cumulativeSum
from sums par
JOIN thetable Child on par.year = child.year - 1
group by child.year,parent.cumulativeSum
)
select * from sums
There's a bit of a "trick" in there grouping on parent.cumulativeSum. We know that this will be the same value for all rows, and we need to add it to sum(child.commitments), so we group on it so SQL Server will let us refer to it. That can probably be cleaned up to remove what might be called a "smell", but it will work.
Warning: 11:15pm where I am, written off the top of my head, may need a tweak or two.
EDIT: forgot the group by in the anchor clause, added that in

Related

Google BigQuery Dimensions SQL Multiple Grids

how would you select multiple grids in the example below instead of just one under "WHERE":
SELECT
sdg_code,
sdg_name,
"grid.5170.3" as grid,
year,
COUNT(DISTINCT id) as pubs,
ROUND(AVG(fcr), 1) as fcr,
ROUND(EXP(AVG(LOG(GREATEST(fcr, 1)))), 1) as fcr_geomean,
ROUND(sum(AltWithScore), 1) as altmetric
FROM
(
SELECT
p.id,
year,
if(p.altmetrics.score > 0, 1, 0) as AltWithScore,
cat_sdg.code as sdg_code,
cat_sdg.name as sdg_name,
p.metrics.field_citation_ratio as fcr,
p.altmetrics.score as altmetric_score,
row_number() over(partition by p.id, cat_sdg.code) as rn
FROM
dimensions - ai.data_analytics.publications p,
UNNEST(category_sdg.full) cat_sdg
WHERE
year >= 2011
AND year <= 2020
AND "grid.5170.3" in UNNEST(research_orgs)
)
WHERE rn = 1
GROUP BY
sdg_code,
sdg_name,
year
ORDER BY year asc
What needs to be changed:
It currently only runs for 1 organisation (GRID), I would like it to run for 11 organisations.
The org is identified with an ID called a “GRID”, it looks like this:
"grid.5170.3"
I want my new code to take 10 org IDs more. Need to use these 10:
grid.5254.6, grid.7048.b, grid.5117.2, grid.10825.3e, grid.4655.2, grid.11702.35, grid.154185.c, grid.475435.4, grid.7143.1, grid.27530.33
And add a column with the org name; currently there is only a column with the org.
Thanks, new to this whole thing.
Instead of WHERE year >= 2011 AND year <= 2020 AND "grid.5170.3" in UNNEST(research_orgs) use below
WHERE year >= 2011 AND year <= 2020
AND EXISTS (
SELECT 1
FROM UNNEST(research_orgs) grid
WHERE grid IN ('grid.5170.3', 'grid.5254.6', 'grid.7048.b', 'grid.5117.2', 'grid.10825.3e', 'grid.4655.2', 'grid.11702.35', 'grid.154185.c', 'grid.475435.4', 'grid.7143.1', 'grid.27530.33')
)

Selecting a second column with a SUM(SUM(value)) function

I am working on a simple query trying to display the total of the totals for 12 periods. I am using a SUM(SUM(value)) function to retrieve the data that I want, however, I am having a hard time displaying a second column in my result.
SELECT CENTRE, SUM(SUM(AMOUNT)) "TOTAL PAY" FROM AB
WHERE ACCOUNT LIKE 'N%' AND CENTRE = '2001' AND YEAR > 2015 GROUP BY AMOUNT, CENTRE;
The error that I am getting has to do with the grouping of the sentence.
Can you please tell me what I have done wrong. I have solved the problem with a sub-query, but I need to fix this query as well because it is used in a more advanced one as a sub-query.
Your questions is too vague to know for sure what you want. For example, what do you mean by "totals for 12 periods"? Is it that for YEAR > 2015 you have 12 rows? Are you always having CENTRE = in your WHERE clause? If so, this might be what you want:
SELECT
MAX(centre) "CENTRE",
SUM(amount) "TOTAL PAY"
FROM
ab
WHERE
account LIKE 'N%'
AND
centre = '2001'
AND
year > 2015;
Or in case CENTRE = 'smth' might not be in your WHERE clause an you need total values for each CENTRE:
SELECT
centre "CENTRE",
SUM(amount) "TOTAL PAY"
FROM
ab
WHERE
account LIKE 'N%'
/* AND
centre = '2001'*/
AND
year > 2015
GROUP BY
centre;
Or in case for every (or one) CENTRE row you need to have total value of all centres:
SELECT
"CENTRE",
total "TOTAL PAY"
FROM
(
SELECT
centre,
ROW_NUMBER() OVER(PARTITION BY
centre
ORDER BY
0
) rn,
SUM(
amount
) OVER(PARTITION BY
0
) total
FROM
ab
WHERE
account LIKE 'N%'
AND
year > 2015
)
WHERE
rn = 1;

MDX for Zero months in last 12 = Number of zero transacting months in the last 12 months rolling window

I am working on MDx query to count the number ZERO txn for each product for last 12 months from today's date. Prepared MDX query for Adventure works fine but my 2nd query running on my Acutal cube working correctly.
Can you please help me out to rectify the query or any filter needed to get correct results like 1st sample query?
1st Sample Query on Adventure Works: (working correctly)
WITH Member [Measures].[Months With Zero Sales] AS
COUNT(
FILTER(
DESCENDANTS(
{[Date].[Calendar].[Month].&[2008]&[1].LAG(12):[Date].[Calendar].[Month].&[2008]&[1]}, [Date].[Calendar].[Month]) ,
[Measures].[Sales Amount] = 0 ) )
SELECT {[Measures].[Months With Zero Sales]} ON 0,
[Product].[Product Model Lines].[Product Line].Members on 1
FROM [Adventure Works];
Product Lines Months With Zero Sales]
----------- -----------------
Accessory 0
Componenets 0
Mountain 0
Road 0
Touring 6
2nd Query on my Cube:
WITH Member [Measures].[Zero Months in last 12] AS
COUNT(
FILTER(
DESCENDANTS(
{[Settlement Date].[Calendar].[Settlement Calendar Month].&[2014]&[1].LAG(12):
[Settlement Date].[Calendar].[Settlement Calendar Month].&[2014]&[1]},
[Settlement Date].[Calendar].[Settlement Calendar Month]),
[Measures].[Transaction Count] = 0 ) )
SELECT {[Measures].[Transaction Count] ,[Measures].[Zero Months in last 12]} ON 0,
[Terminal].[terminal ID].members on 1
FROM [cubetxn]
I'm expecting if non zero where "transaction count" is (null), even if there is transaction count not null, there could be chances to have one month with empty tuples.
Can you please correct my query or someone can give me sample query which should able to give me total zero month txn count for last 12 month of each product.
Terminal ID Transaction Count Zero Months in last 12
---------- ----------------- -------------------------
All Terminals 504,112,053 0
Q1001 138,832 0
Q1002 (null) 0
Q1003 88,800 0
Q1004 (null) 0
First comment is that this is a quicker pattern to use when doing a count/filter:
WITH
MEMBER [Measures].[Months With Zero Sales] AS
Sum
(
Descendants
(
{
[Date].[Calendar].[Month].&[2008]&[1].Lag(12)
:
[Date].[Calendar].[Month].&[2008]&[1]
}
,[Date].[Calendar].[Month]
)
,IIF
(
[Measures].[Sales Amount] = 0
,1
,null
)
)
SELECT
{[Measures].[Months With Zero Sales]} ON 0
,[Product].[Product Model Lines].[Product Line].MEMBERS ON 1
FROM [Adventure Works];
Based on this more efficient approach does the following work?
WITH
MEMBER [Measures].[Zero Months in last 12] AS
Sum
(
Descendants
(
{
[Settlement Date].[Calendar].[Settlement Calendar Month].&[2014]&[1].Lag(12)
:
[Settlement Date].[Calendar].[Settlement Calendar Month].&[2014]&[1]
}
,[Settlement Date].[Calendar].[Settlement Calendar Month]
)
,IIF
(
[Measures].[Transaction Count] = 0
,1
,0
)
)
SELECT
{
[Measures].[Transaction Count]
,[Measures].[Zero Months in last 12]
} ON 0
,[Terminal].[terminal ID].MEMBERS ON 1
FROM [cubetxn];
If there is still a problem then why not reconstruct your script so you can manually check what to expect. So for the AdvWrks script I'd run this so that I could actually confirm that the 6 is correct:
SELECT
{[Measures].[Sales Amount]} ON 0
,
Descendants
(
{
[Date].[Calendar].[Month].&[2008]&[1].Lag(12)
:
[Date].[Calendar].[Month].&[2008]&[1]
}
,[Date].[Calendar].[Month]
)
*
[Product].[Product Model Lines].[Product Line].MEMBERS ON 1
FROM [Adventure Works];
So against your cube what does the following return?
SELECT
{[Measures].[Transaction Count]} ON 0
,
Descendants
(
{
[Settlement Date].[Calendar].[Settlement Calendar Month].&[2014]&[1].Lag(12)
:
[Settlement Date].[Calendar].[Settlement Calendar Month].&[2014]&[1]
}
,[Settlement Date].[Calendar].[Settlement Calendar Month]
)
*
[Terminal].[terminal ID].MEMBERS ON 1
FROM [cubetxn];
//Total Transactions count Weekend Sunday (i’ve date dimesion which holds day_in_week=’Sun’ for respective dates)
WITH SET AllTranSundays as
EXISTS(DATE.DATE.DATE.MEMBERS, DATE.DATE.day_in_week.&[Sun], "Sales")
//Count of all sundays which had transactions.
MEMBER Measures.CntAllTranSundays AS
COUNT(AllTranSundays)
//YTD Days = Count of days within calendar year to date
MEMBER Measures.CntDaysYTD as
COUNT(DESCENDANTS(ANCESTOR([DATE].[date].CURRENTMEMBER,
3), 3).item(0).item(0)
: [DATE].[date].CURRENTMEMBER)
//YTD Transactions = Transaction count year to date
MEMBER Measures.CntTranYTD as
COUNT(
EXISTS(
{DESCENDANTS(ANCESTOR([DATE].[date].CURRENTMEMBER,
3), 3).item(0).item(0)
: [DATE].[date].CURRENTMEMBER}, , "Sales"
)
//Zero months in last 12 = Number of zero transacting months in the last 12 months rolling window
MEMBER Measures.CntZeroTransactingMonths as
COUNT(
{ANCESTOR([DATE].[date].CURRENTMEMBER, 1).ITEM(0).LAG(12) : ANCESTOR([DATE].[date].CURRENTMEMBER, 1).ITEM(0)}
-
EXISTS({ANCESTOR([DATE].[date].CURRENTMEMBER, 1).ITEM(0).LAG(12) : ANCESTOR([DATE].[date].CURRENTMEMBER, 1).ITEM(0)}
, ,
"Sales")
)
//Consecutive zero months = Number of consecutive zero transacting months in last 12 months rolling window
Question Do you want a count of instances when consecutive months had zero transactions.
Or do you want a count of number of months which had consecutively no transactions?
What I am trying to say is say Jan, March, June, July, August, October, November had no transactions in the rolling last 12 months
As per case 1: the answer should be 2
As per case 2: the answer should be 5.
Will update my answer as per your clarification.
SELECT
{Measures.CntAllTranSundays, Measures.CntDaysYTD, Measures.CntTranYTD, Measures.CntZeroTransactingMonths} ON 0
FROM [YourCube]
where
[date].[date].[date].&[02/28/2015]

SQL:Pivot table which includes sum and percentage total

I'm trying to recreate a view in Tableau as a view in SQL. It requires me pivoting a table based on month and not only summing the amount but I also need to sum by margin and also create a Margin % row.The desired output is
BUSINESS_UNIT CLASS JANUARY FEBRUARY MARCH
202 Cost of Sales 100 (null) 60
202 Revenue 200 80 (null)
202 Margin x xx xxx
202 Margin % x% xx% xxx%
I can pivot based on Month but how do perform twos sums in one pivot table and how would I go about including a percenatge row also?
Code so far
SELECT
*
FROM
(SELECT
[Business_Unit]
,[Class]
,Month as Period
,[Amount]
--,Margin
FROM [sample_table]
where [Class] in ('Revenue','Cost of Sales') )AS T
PIVOT(SUM(Amount)
FOR Period IN ([January],[February],[March])) as Pvt
I have included my code so far http://www.sqlfiddle.com/#!3/06bafc/6
Not the prettiest SQL I've done. but this seems to work...
http://www.sqlfiddle.com/#!3/06bafc/60/0
What it does is build on what you've done by generating a margin line and adding a total column
Using this line and total we can then calculate the % of margin. Grouping SETS allowed me to generate the multiple rows, subtotals and totals, Since I knew the only additional line generated would have a null class, I was able to set the Name of the class to margin when null.
WITH CTE AS (
SELECT
Business_Unit
,case when class is NULL then 'Margin' else class end as Class
,Sum(January) as January
,Sum(February) as February
,Sum(March) as march
,Sum(coalesce(January,0)+coalesce(February,0)+coalesce(March,0)) as Total
FROM (
SELECT
*
FROM
(SELECT
[Business_Unit]
,[Class]
,Month as Period
,[Amount]
--,Margin
FROM [sample_table]
where [Class] in ('Revenue','Cost of Sales') )AS T
PIVOT(SUM(Amount)
FOR Period IN ([January],[February],[March])) as Pvt
) as Base
GROUP BY Grouping sets
((Business_Unit,Class,January,February,March,
coalesce(January,0)+coalesce(February,0)+coalesce(March,0))
,(Business_Unit)
))
SELECT *
FROM CTE UNION
SELECT Business_Unit
,'Margin %'
,January*100.00/Total
,February*100.00/Total
,March*100.00/Total
,Total*100.00/Total
FROM CTE
WHERE CLASS='Margin'

SQL query to identify seasonal sales items

I need a SQL query that will identify seasonal sales items.
My table has the following structure -
ProdId WeekEnd Sales
234 23/04/09 543.23
234 30/04/09 12.43
432 23/04/09 0.00
etc
I need a SQL query that will return all ProdId's that have 26 weeks consecutive 0 sales. I am running SQL server 2005. Many thanks!
Update: A colleague has suggested a solution using rank() - I'm looking at it now...
Here's my version:
DECLARE #NumWeeks int
SET #NumWeeks = 26
SELECT s1.ProdID, s1.WeekEnd, COUNT(*) AS ZeroCount
FROM Sales s1
INNER JOIN Sales s2
ON s2.ProdID = s1.ProdID
AND s2.WeekEnd >= s1.WeekEnd
AND s2.WeekEnd <= DATEADD(WEEK, #NumWeeks + 1, s1.WeekEnd)
WHERE s1.Sales > 0
GROUP BY s1.ProdID, s1.WeekEnd
HAVING COUNT(*) >= #NumWeeks
Now, this is making a critical assumption, namely that there are no duplicate entries (only 1 per product per week) and that new data is actually entered every week. With these assumptions taken into account, if we look at the 27 weeks after a non-zero sales week and find that there were 26 total weeks with zero sales, then we can deduce logically that they had to be 26 consecutive weeks.
Note that this will ignore products that had zero sales from the start; there has to be a non-zero week to anchor it. If you want to include products that had no sales since the beginning, then add the following line after `WHERE s1.Sales > 0':
OR s1.WeekEnd = (SELECT MIN(WeekEnd) FROM Sales WHERE ProdID = s1.ProdID)
This will slow the query down a lot but guarantees that the first week of "recorded" sales will always be taken into account.
SELECT DISTINCT
s1.ProdId
FROM (
SELECT
ProdId,
ROW_NUMBER() OVER (PARTITION BY ProdId ORDER BY WeekEnd) AS rownum,
WeekEnd
FROM Sales
WHERE Sales <> 0
) s1
INNER JOIN (
SELECT
ProdId,
ROW_NUMBER() OVER (PARTITION BY ProdId ORDER BY WeekEnd) AS rownum,
WeekEnd
FROM Sales
WHERE Sales <> 0
) s2
ON s1.ProdId = s2.ProdId
AND s1.rownum + 1 = s2.rownum
AND DateAdd(WEEK, 26, s1.WeekEnd) = s2.WeekEnd;