Optimize query for for cumulative result - sql

I have this query to find out item count for every month of year. But I am looking for a optimized query for cumulative result
SELECT
COUNT(ITM.ID) AS ItemCount,
Month(ITM.ItemProcureDate),
Year(ITM.ItemProcureDate)
FROM
Rpt_Item ITM
WHERE
ITM.ItemProcureDate IS NOT NULL
AND
ITM.ItemStatusID = 2 -- Item sold, Item Rejected
AND
ITM.ItemProcureDate >= CONVERT(DATETIME,'02/01/2014',1) --#Beg_Date
AND
ITM.ItemProcureDate <= CONVERT(DATETIME,'04/12/2014',1) --#End_Date
GROUP BY
Month(ITM.ItemProcureDate),
Year(ITM.ItemProcureDate)
Query result should be like this:
Item sold In month 2
Item Sold Till Month 2
Item Rejected 1
Item Rejected Till Month 1
Year 2014
Month Feb
Last Date of Month 02/28/2014
-----------------------------------------------
Item sold In month 2
Item Sold Till Month 4
Item Rejected 1
Item Rejected Till Month 2
Year 2014
Month March
LastDate of Month 03/31/2014
-----------------------------------------------
Item sold In month 2
Item Sold Till Month 6
Item Rejected 1
Item Rejected Till Month 3
Year 2014
Month April
Last Date of Month 04/30/2014
I have to find out Item_Sold, Item_Rejected, Item_Added for last three months where every next month it should be cumulative of all previous months values of Item_Sold, Item_Rejected, Item_Added

In SQL Server 2008, you can do this using a correlated subquery or using a non-equijoin. SQL Server 2012 supports a cumulative sum function. Here is a way to do it with a correlated subquery:
with ym as (
SELECT COUNT(ITM.ID) AS ItemCount,
Month(ITM.ItemProcureDate) as mon, Year(ITM.ItemProcureDate) as yr,
Month(ITM.ItemProcureDate) + 100*Year(ITM.ItemProcureDate) as yyyymm
FROM Rpt_Item ITM
WHERE ITM.ItemProcureDate IS NOT NULL AND
ITM.ItemStatusID = 2 AND
ITM.ItemProcureDate >= CONVERT(DATETIME,'02/01/2014',1) AND
ITM.ItemProcureDate <= CONVERT(DATETIME,'04/12/2014',1)
GROUP BY Month(ITM.ItemProcureDate), Year(ITM.ItemProcureDate)
)
select ym.*,
(select sum(ItemCount)
from ym ym2
where ym.yyyymm <= ym.yyyy.mm
) as cumsum
from ym;
Note that this puts the year-month into a YYYYMM format. This is just a convenience so the comparison on the time period uses only one column.
Also, if the ITM table is really big or is a view, then this might not perform as well as one would like. If performance is an issue, use a temporary table instead of a CTE. (SQL Server tends not to materialize CTEs so it is likely to run the code twice.)

Related

getting sum for each month for several months in a year in sql

I have the following table
image of database in use
i want to get the following kind of results
jan 12500
feb 16500
mar 4500
apr 6500
the query should return a total for each month for desired months.
i know how to do this..
$sql = "SELECT SUM(cost) as january FROM earnings WHERE month= 1 and year= '$2022" ;
to get the sum for a given month but I cant find anything on how to get multiple months at once.
am still new to this
SELECT
SUM(cost) as cost,
month
FROM earnings
WHERE year = :year
GROUP BY month
Sum all entries of cost, per month (GROUP BY) found in year (:year)
Each ROW will have a column cost and month.
If you want to "further" filter the months you can apply another AND clause
AND (month >= 1 OR month <= 6) for January to June
Useful Source:
https://www.mysqltutorial.org/mysql-group-by.aspx

SQL Query to recursively track month of purchase

I have a table with customer id and month of purchase. For each customer, I first need to segment them on their first month of purchase, i.e., if a customer did their first purchase on 10 June 2017, then they belong to bucket June 2017. See below sample data table.
Then for each subsequent purchase of that customer (say from June 2017 segment), we need to track the month. For instance, if the June 2017 customer did their second purchase on 25 June 2017 and 3rd purchase on 11 Aug 2017. Then second purchase will be counted in 1st Month (within 30 days of 1st transaction) and 3rd purchase will be counted in 3rd month, as difference between 11 Aug 2017 and 10 June 2017 is 62 days, which lies between 61 and 90 days, hence in the 3rd month.
See below sample output table, although I need it in percentage form (% of customer who did in first month, second month, etc.). In the table, we are showing all the customers who did their first transaction say in Jan 2017 and then how many of them did transactions in subsequent months.
This tracking needs to be done for each customer. While I believe I am comfortable with the first part, wherein I need to segment each customer, I can do that based on first or partition.
I am not sure about how to do this recursively for subsequent transactions.
Thanks in advance for help!
You simply use window functions to define the original month and then conditional aggregation.
You don't mention the database, but this is the idea:
select to_char(first_purchase_date, 'YYYY-MM') as yyyymm,
sum(case when months_between(first_purchase_date, purchase_date) = 1 then 1 else 0 end) as purchases_1,
sum(case when months_between(first_purchase_date, purchase_date) = 1 then 1 else 0 end) as purchases_2,
. . .
from (select t.*,
min(purchase_date) over (partition by customer_id) as first_purchase_date
from t
) t
group by first_purchase_date;
I invented the months_between() and to_char() functions, but you should get the idea.
The above tracks purchases. To get customers, you can use:
(count(distinct case when months_between(first_purchase_date, purchase_date) = 1 then customer_id) /
count(distinct customer_id)
) as month_1_ratio
You can use the lag function to create a column “previous purchase.
Lag(purchasemonth,1) over(partition. by customerid order by purchasemonth) as [PreviousPurchaseDate]
Then simply do a datediff and bucket as you wish.

How to make a (MDX) calculation in a SSAS cube to get the difference between a value from the current row and a value from the previous row?

I would like to make a calculation to get the difference between the departDate from my current row and the arriveDateNextStop from my previous row. I have a fact table which has multiple columns. The three most important columns are: id, departDate, arriveDateNextStop.
If I have for example these two rows in my fact table:
id departDate arriveDateNextStop
1 01-01-2019 03-01-2019
1 04-01-2019 07-01-2019
Explanation: On 1 January 2019 I depart to the next destination and I arrive there on 3 January 2019. On 4 January 2019 I again depart to the next destination and I arrive there on 7 January 2019.
Now I would like to know how many days the idle time was (the amount of days between the arrival and the next depart). So with this example the idle time would be 1, because between 3 January 2019 and 4 January 2019 is one day.
First, I made this 'calculation' in Management Studio as a SQL query. See query below:
SELECT s.Id, s.departDate as Depart_current_place, s.arriveDateNextStop as Arrival_next_stop, LAG(arriveDateNextStop) OVER (ORDER BY arriveDateNextStop) AS Arrival_current_stop, DATEDIFF(DAY, LAG(arriveDateNextStop) OVER (ORDER BY arriveDateNextStop), departDate) AS Amount_of_days
FROM MyTable s
WHERE Id = 9
GROUP BY s.departDate, s.Id, s.arriveDateNextStop
ORDER BY s.departDate
This query works fine, but how can I do this in my cube as a calculation in MDX?
I don't have the same example, but the similar cube structure with Completed/Received date:
with
member departDate as [Received].[Year Qtr Month].CurrentMember.Member_Key
member arriveDate as [Completed].[Year Qtr Month].CurrentMember.Member_Key
member arriveDateNextStop as [Completed].[Year Qtr Month].CurrentMember.Lead(1).Member_Key
member idleDays as departDate-arriveDateNextStop
SELECT NON EMPTY { departDate,arriveDate,arriveDateNextStop,idleDays } ON 0
, NON EMPTY
{ ([Completed].[Year Qtr Month].[Date].ALLMEMBERS
* [Received].[Year Qtr Month].[Date].ALLMEMBERS ) } ON 1
FROM ( SELECT ( { [Completed].[Year Qtr Month].[Date].&[6213] } ) ON COLUMNS
FROM [MyCube])
I also have integer key for a date dimension (CurrentMember.Member_Key). 1 = 1998-01-01, 2 = 1998-01-02 etc. till today. You need to create a property in a Date dimension if your Date key is classic YYYYMMDD (which you cannot subtract to get days difference, I can do that in my example). And use it like CurrentMember.Properties("property name") instead of Member_Key.
Main formula part: Lag/Lead function to get prev. or next member.
Please update in case of questions.

SQL check if date exists in the next 2 years

I have a table where each record has multiple dates saved in the date column such as Record ID '01' can have 6 rows with dates each from 2015, 2016, 2017, 2018 and 2019. Each record ID only has one date per year.
I am interested to see for all record ID that have a date in the current year, if they have a date in the next 2 years (i.e Record ID has a date from 2017 and 2018), just the next year (Record ID only has a date from 2017) or just this year.
I am not interested in records that do not have a date in the current year even if they may have dates in the next 2 years. I am also not interested in records that may have a date 3 years from now but not have a date in the next 2 years.
Thanks in advance.
Based on your question. Try this.
Updated.
Select RecordID, Year(DateColumn)
From table
Where Year(DateColumn) Between Year(GetDate()) and (Year(GetDate()) + 2)
Group By RecordID, Year(DateColumn)
Having Count(1) = 3

SQL: Calculate the number of Days in a Month with no stock

I am trying to create a query than can calculate the number of days, in a given month, that a particular stock item was unavailable (ie: No. = 0).
Currently, I have developed a query that can calculate the number of days it has been from today's date where stock has been unavailable but what I am trying to actually calculate is, during a month, how many days was stock quantity = 0. ie: Month of Jan - on Jan 5, Jan 7 and Jan 20 there was no stock for Item A - this means that the number of days out of stock was = 3.
Extra Details:
Currently, I am basing my query in determining stock levels of the last transaction (ie: if, at the last transaction, the QTY of Stock = 0) then calculate the number of days between the transaction date and today.
Select [StockItems].StockCode,
Case When SUM([StockItems].Qty_On_Hand)=0 Then (Datediff(day, GETDATE(),MAX([Transactions].TransactionDate))) ELSE 0 END AS 'Days Out of Stock',
From dbo.[Transactions]
INNER JOIN [StockItems]
ON [Transactions].[AccountLink] = [StockItems].[StockLink]
Where [StockItems].StockCode LIKE '%XXX%'
AND [Transactions].TransactionDate>31/10/14
Group By [StockItems].StockCode
My Thoughts
There are different sorts of transactions - one of which is a good received transaction. Perhaps it is possible to calculate the days where Stock Qty was zero and a transaction occurred then count that date until goods were received.
Thoughts?
Thank You.
SELECT COUNT([StockItems].Qty_On_Hand
From dbo.[Transactions]
INNER JOIN [StockItems] ON [Transactions].[AccountLink] = [StockItems].[StockLink]
WHERE [StockItems].Qty_On_Hand)=0