Dynamically select date - mdx

Goal is to pass prior year if current month is 1, else pass current year. I always want data through the prior month. I have dynamic month logic working, just the year is causing me issues. I am attempting this with an IIF statement but am consistently returning the current year.
SELECT ( { IIF( Month(Now()) = '1', Strtomember(" [Posting Date].[Year].&[" + cstr(year(dateadd('yyyy',-1,now()))) + "] "),
Strtomember(" [Posting Date].[Year].&[" + cstr(year(now())) + "] "))
} ) ON COLUMNS
I have verified that each Strtomember piece works correctly independently when I remove the IIf. I am able to query current year and then swap the Strtomember and return current year -1.
Note: For testing purposes I have IIF( Month(Now()) = '6' as it is the current month at time of post. I should return current year -1, but am returning current year.

Try changing the '1' to just a number 1:
Instead of Month(Now()) = '1'
Use Month(Now()) = 1
The above change works fine on my cube:
SELECT
{
IIF
(
Month(Now()) = 6
,StrToMember
("[Date].[Date - Calendar Month].[Calendar Year].&["
+
Cstr(Year(Dateadd('yyyy',-1,Now())))
+ "]"
)
,StrToMember
(
"[Date].[Date - Calendar Month].[Calendar Year].&[" + Cstr(Year(Now()))
+ "] "
)
)
} ON COLUMNS

Related

How to get customers who have most purchases in past 365 days, but none before?

I am having trouble writing this sql query. Basically I need to find the top 100 sCompanys who had the most nSales within the last 365 days, but had zero sales before 365 days. This is being done in node so its a string, I am also passing in parameters. Start date is the date for 365 days ago.
This is not throwing any errors when I run it, however it also is not returning any data.
getMostSales365NoneBefore(startDate) {
let sqlQuery = '';
sqlQuery =
"SELECT TOP 100 SUM(nQuoteTotal) AS nSales, sCompany FROM Customer_Quotes WHERE (bDeleted=0 AND sStatus='Closed' AND dtFirstClosed > " +
"'" +
startDate +
"')" +
' AND (nSales < ' +
"'" +
startDate +
"') IS NOT NULL" +
' GROUP BY sCompany ORDER BY nSales DESC';
console.log(sqlQuery);
return sqlQuery;
}, ```
You should parameterize your query properly, and pass through #startDate as a parameter.
Note that you cannot refer to aggregates in the WHERE part, only in the HAVING, ORDER BY or SELECT
The query you want would look like this
SELECT TOP (100)
SUM(CASE WHEN dtFirstClosed >= #startDate THEN nQuoteTotal END) AS nSales,
sCompany
FROM Customer_Quotes
WHERE bDeleted = 0
AND sStatus = 'Closed'
GROUP BY sCompany
HAVING COUNT(CASE WHEN dtFirstClosed < #startDate THEN 1 END) = 0
ORDER BY nSales DESC

SQL Server 2012 - Running Total With Backlog & Carry Forward

Good afternoon,
Hope that you're all well and wish you a happy new year.
I'm experiencing some curious behaviour with a query that I've written in that the LAG function is inconsistent.
Essentially, I have a dataset (made up of 2 CTEs) which each contain the month (in MMM-YYYY format) and then one holds a count of tickets opened, and the other contains the same but for tickets closed.
What I am then doing is adding in a 'Backlog' column (which will be 0 for the first month in all cases) and a 'Carried Forward' column. The Carried Forward amount will be the balance of that month ( Created + Backlog ) and will be reflected as the Backlog for the following month.
I had this ticking over quite nicely until I realised that negative backlogs were fudging the numbers a bit. What I mean is, for example:
10 Tickets Created
12 Tickets Resolved
0 Ticket Backlog
-2 Tickets Carried Forward
In this circumstance, I've had to zero any negative backlog for our reporting purposes.
This is seemingly where the problems come into play. For the first few months, everything will be fine - the values will be right, carrying forward the correct numbers and factoring them into the calculations accordingly. But then it will carry over a number of (seemingly) indeterminable origin which of course, has a knock-on effect on the accuracy past this point.
With the Window Functions introduced with SQL Server 2012, this should be quite basic - but evidently not!
Whilst I'm quite happy to post code (I have tried a fair few ways of skinning this cat), I feel as though if someone is able to give a high-level overview of how it should be written, I'll see where I went wrong immediately. In doing so, I'll then respond accordingly with my attempt/s for completeness.
Thank you very much in advance!
Picture of result error:
, OpenClosed AS
(
SELECT
c.[Created Month] 'Month'
, c.Tickets 'Created'
, r.Tickets 'Resolved'
, IIF( ( c.Tickets - r.Tickets ) < 0, 0, ( c.Tickets - r.Tickets ) ) 'Balance'
FROM
Created c
JOIN Resolved r ON
c.[Created Month] = r.[Resolved Month]
)
, CarryForward AS
(
SELECT
ROW_NUMBER() OVER( ORDER BY CAST( '1.' + Month AS DATETIME ) ) 'Row No'
, Month 'Month'
, Created 'Created'
, Resolved 'Resolved'
, LAG( Balance, 1, 0 ) OVER( ORDER BY CAST( '1.' + Month AS DATETIME ) ) 'Backlog'
, IIF( ( ( Created + LAG( Balance, 1, 0 ) OVER( ORDER BY CAST( '1.' + Month AS DATETIME ) ) ) - Resolved ) < 0
, 0
, ( ( Created + LAG( Balance, 1, 0 ) OVER( ORDER BY CAST( '1.' + Month AS DATETIME ) ) ) - Resolved )
) 'Carry Forward'
FROM
OpenClosed
)
SELECT
c1.Month 'Month'
, c1.Created 'Created'
, c1.Resolved 'Resolved'
, c2.[Carry Forward] 'Backlog'
, IIF( ( c1.Created + c2.[Carry Forward] ) - c1.Resolved < 0
, 0
, ( c1.Created + c2.[Carry Forward] ) - c1.Resolved
) 'Carried Forward'
FROM
CarryForward c1
JOIN CarryForward c2 ON
c2.[Row No] = c1.[Row No]-1
From comments on question. Incidentally, the Created Month column should be redone somehow so that the year is placed before the month - like 2015-01. This will ensure correct ordering by default sort algorithms.
If the date must be presented as Jan-2015 in the final report, do that presentational work as the very final step in the query.
WITH ticket_account AS
(
SELECT
c.[Created Month] AS Month
,c.Tickets AS Created
,r.Tickets AS Resolved
FROM
Created AS c
INNER JOIN
Resolved AS r
ON c.[Created Month] = r.[Resolved Month]
)
SELECT
*
,(SUM(Created) OVER (ORDER BY Month ASC) - SUM(Resolved) OVER (ORDER BY Month ASC)) AS Balance
FROM
ticket_account

If Then Else in WHERE clause in MS Access SQL Query

I'm trying out MS Access SQL Query. My Data is structured like this
Rent Table
The idea is I want to split the table to collect the latest start up to 12 months back using [Year_Start] and [Month_Start] as basis. So my rough code will be:
SELECT [Renter_Name], [Amount]
FROM RentTable1
WHERE [Year_Start] = Max([Year_Start]) AND [Month_Start] = Max([Month_Start])
ORDER BY [Renter_Name];
Subsequently, other month tables will conceptually be coded like this:
SELECT [Renter_Name], [Amount]
FROM RentTable1
WHERE [Year_Start] = Max([Year_Start]) AND [Month_Start] = Max([Month_Start]) - 1
ORDER BY [Renter_Name];
And then subsequent months will be adjusted using the minus sign.
SELECT [Renter_Name], [Amount]
FROM RentTable1
WHERE [Year_Start] = Max([Year_Start]) AND [Month_Start] = Max([Month_Start]) - 2
ORDER BY [Renter_Name];
I'm also considering a case where [Month_Start] = Max([Month_Start]) - x will be zero (0) or a negative number so a theoretical code will be:
SELECT [Renter_Name], [Amount]
FROM RentTable1
IF Max([Month_Start]) - X <= 0 THEN
WHERE [Year_Start] = Max([Year_Start]) - 1 AND [Month_Start] = Max([Month_Start]) - X
ELSE
WHERE [Year_Start] = Max([Year_Start]) AND [Month_Start] = Max([Month_Start]) - X
END IF
ORDER BY [Renter_Name];
*** X being the months backward from the latest start month and year.
Clearly, you see my SQL coding skills are really weak. Pardon me as I'm really a beginner. So there are some touches other standard programming like If-Then-Else statements.
I was hoping someone could propose to correct the above codes.
Thanks! Appreciate everyone who stumble upon this question.
EDIT 1:
Just to clarify, this is the expected thought:
In the example the latest period is 2016 and 4. So it should pick it up for TABLE1.
A subsequent query is to be made to minus one month from the latest period so the result should be 2016 and 3. This goes on until 2016 and 1.
When 4 - 4 happens which equals 0, the query should be able to skip through this illogical step and go through (2016 - 1) and the get the max month using the result of (2016 - 1) which is 2015 and 12.
First of all, here is my advise: when dealing with dates use the DATE data type. You can specify the StartDate as 2016-04-01 and the EndDate as 2017-04-31. Even better: specify the EndDate as 2017-05-01 and always remember that you need to use >= for the StartDate and < for the EndDate.
Now, to your problem. You need to convert the columns to the proper date using the [DateSerial()][1] function, like this:
SELECT [Renter_Name], [Amount]
FROM RentTable1
WHERE DateSerial([Year_Start], [Month_Start], 1) =
(SELECT Max(DateSerial([Year_Start], [Month_Start], 1) as dt FROM RentTable1)
ORDER BY [Renter_Name];
To get the details for the previous month use DateAdd() function. Here is the example for the previous month:
SELECT [Renter_Name], [Amount]
FROM RentTable1
WHERE DateSerial([Year_Start], [Month_Start], 1) =
(SELECT DateAdd('m', -1, Max(DateSerial([Year_Start], [Month_Start], 1)) as dt FROM RentTable1)
ORDER BY [Renter_Name];
And here is the universal query to get the details for the X months ago:
SELECT [Renter_Name], [Amount]
FROM RentTable1
WHERE DateSerial([Year_Start], [Month_Start], 1) =
(SELECT DateAdd('m', [X] * (-1), Max(DateSerial([Year_Start], [Month_Start], 1)) as dt FROM RentTable1)
ORDER BY [Renter_Name];

Transposing number from one column into another one where = 0

My question is this,
I have a query I'm working on and I have some values that are 0. I want to be able to take a value from a previous month that is not zero and put it in place of the zero. See the example below.
SELECT item,
stock,
sold,
level,
month,
year
FROM agingdata
GROUP BY item,
stock,
sold,
month,
year,
level
HAVING ( item = #Item )
ORDER BY year,
month
So I want take the number 2455 and input it into the stock where it says 0, taking last months balance number as the current months stock level. Is that even possible?
You can find the previous non-zero level per item (for zero level items) using this query:
SELECT find.item, find.month, find.year, result.level
FROM AgingData result
JOIN (
SELECT original.item, original.month, original.year, max(cast(cast(previous.year as varchar) + '-' + cast(previous.month as varchar) + '-1' as datetime)) previous_date
FROM AgingData original
JOIN AgingData previous
ON original.item = previous.item
AND ((original.year > previous.year)
OR (original.year = previous.year AND original.month > previous.month))
WHERE original.level = 0
AND previous.level != 0
GROUP BY original.item, original.month, original.year ) find
ON result.item = find.item
AND cast(cast(result.year as varchar) + '-' + cast(result.month as varchar) + '-1' as datetime) = find.previous_date
This will work even if the previous non-zero level is several months before.
Something along these lines, this only works if the previous month is non-zero....
SELECT cur.Item,
CASE
WHEN (cur.Stock<>0)
THEN cur.Stock
ELSE prev.Stock
END as Stock,
cur.Sold,
cur.Level,
cur.Month,
cur.Year
FROM AgingData cur
LEFT OUTER JOIN AgingData prev
ON prev.item=cur.item and prev.Month = cur.Month - 1
GROUP BY cur.Item, cur.Stock, cur.Sold, cur.Month, cur.Year, cur.Level
HAVING (cur.Item = #Item)
ORDER BY cur.Year, cur.Month

Building up a monthly total from past 12 months

CurrentMonth = Month(CurrentDate)
CurrentYear = Year(CurrentDate)
SQL = "SELECT Spent, MONTH(Date) AS InvMonth, YEAR(Date) As InvYear FROM Invoices WHERE YEAR(Date) = '" & CurrentYear & "' AND MONTH(Date) = '" & CurrentMonth & "'"
RecordSet.Open SQL, Connection, adOpenStatic, adLockOptimistic, adCmdText
Do Until RecordSet.EOF
MTotal(i) = MTotal(i) + RecordSet.Fields("Spent")
RecordSet.MoveNext
Loop
RecordSet.Close
This is the code I currently have to build up a total spent for a given month.
I wish to expand this to retrieve the totals per month, for the past 12 months.
The way I see to do this would be to loop backwards through the CurrentMonth value, and if CurrentMonth value reaches 0 roll the value of CurrentYear back 1. Using the loop variable (i) to build up an array of 12 values: MTotal()
What do you guys think?
A group by should get you on the way.
SELECT TOP 12
SUM(Spent) AS Spent
, MONTH(Date) AS InvMonth
, YEAR(Date) AS InvYear
FROM
Invoices
GROUP BY
YEAR(Date), MONTH(Date)
WHERE DATEDIFF(mm, Date, GETDATE(()) < 12
Josh's DATEDIFF is a better solution than my original TOP and ORDER BY
I would tackle this by "rounding" the date to the Month, and then Grouping by that month-date, and totalling the Spent amount:
SELECT SUM(Spent) AS [TotalSpent],
DATEADD(Month, DATEDIFF(Month, 0, [Date]), 0) AS [MonthDate]
FROM Invoices
WHERE [Date] >= '20080301'
AND [Date] < '20090301'
GROUP BY DATEADD(Month, DATEDIFF(Month, 0, [Date]), 0)
ORDER BY [MonthDate]
The [MonthDate] can be formatted to show Month / Date appropraitely, or in separate columns.
The WHERE clause can be parameterised to provide a suitable range of records to be included
The only problem with this is that I require a monthly total, for each of the past 12 months rather then the total for the past 12 months. Otherwise I see how improving the SQL rather then using vb6 code oculd be a better option.
The solution I came up with would be :
For i = 0 To 11
If CurrentMonth = 0 Then
CurrentMonth = 12
CurrentYear = CurrentYear - 1
End If
SQL = "SELECT Spent, MONTH(Date) AS InvMonth, YEAR(Date) As InvYear FROM Invoices WHERE YEAR(Date) = '" & CurrentYear & "' AND MONTH(Date) = '" & CurrentMonth & "'"
RecordSet.Open SQL, Connection, adOpenStatic, adLockOptimistic, adCmdText
Do Until RecordSet.EOF
MTotal(i) = MTotal(i) + RecordSet.Fields("Spent").Value
RecordSet.MoveNext
Loop
RecordSet.Close
CurrentMonth = CurrentMonth - 1
Next
I believe this should work as expected. However I still look forward to seeing what solutions you guys can come up, or if anyone spots an issue with ym fix.