SQL Server query to get data for last two months - sql

SELECT
DAY(table_A.PaymentDate) as date1 ,
(CASE
WHEN MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP)
THEN CAST(SUM(table_A.Total_Amount) As INT)
ELSE 0
END) AS This_month_CNT,
(CASE
WHEN MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP) - 1
THEN CAST(SUM(table_A.Total_Amount) AS INT)
ELSE 0
END) AS last_month_CNT
FROM
Tbl_Pan_Paymentdetails table_A
FULL OUTER JOIN
Tbl_Pan_Paymentdetails table_B ON table_A.PaymentDate = table_B.PaymentDate
WHERE
YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND table_A.PaymentDate >= DATEADD(MONTH, -2, GETDATE())
GROUP BY
DAY(table_A.PaymentDate),
MONTH(table_A.PaymentDate)
ORDER BY
DAY(table_A.PaymentDate) ;

Not sure I fully understand.
WHERE YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP) AND
table_A.PaymentDate >= DATEADD(MONTH, -2, GETDATE())
Here you are (1) comparing the Year elements of your payment date with CURRENT_TIMESTAMP, and (2) making sure the payment date is greater than the last 2 months based on GETDATE()?
Not sure why you are using both CURRENT_TIMESTAMP and GETDATE(). Either way, I think the second part of that WHERE statement does what you want.
If the current date is January 31, 2015, your currently logic will not return any records from December 2014. The first part of your where statement is filtering them out. If you really want the last 2 months, remove the following from the WHERE statement
YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP) AND

Related

How to return values of two date ranges, from the same date column and value column, in two different columns as a result?

I have following data in my table,
Table = BillHeader
Sales column = Sales
Date column = CreateDate
Location name = Location
Result needed:
Location
Sum_of_Sale_1
Sum_of_Sale_2
Sum_of_Sale_1 = Sum of Sales up to yesterday for this month.
Sum_of_Sale_2 = Sum of Sales up to same date range as Sum_of_Sale_1 during last month.
For example, if today is 20th of June, Sum_of_Sale_1 = Sum of sales from 1st June to 19th of June
and Sum_of_Sale_2 = Sum of sales from 1st May to 19th of May.
Basically what I need is these two results of different date ranges, which should be selected form the same three columns, should appear next to each other in the result. I want to know how the sales performance was last month's same date range as to this month's date range (up to yesterday for this month).
Thanks!!
EDIT - 1
Here is the actual current working code:
SET #FDM = DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), 0)
SELECT sum ([LAB_TRN_BillHeader].[AmountToBePaid]) as Total_Sale
,LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode]
,LAB.dbo.[LAB_Comm_MST_CollectingCenter].[Name]
,LAB.dbo.[LAB_Comm_MST_Branch].[BranchName]
FROM Lab.dbo.[LAB_TRN_BillHeader]
INNER JOIN LAB.dbo.[LAB_Comm_MST_CollectingCenter] on LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode] = LAB.dbo.[LAB_Comm_MST_CollectingCenter].[CollectingCenterCode]
INNER JOIN LAB.dbo.[LAB_Comm_MST_Branch] on LAB.dbo.[LAB_TRN_BillHeader].[BranchCode] = LAB.dbo.[LAB_Comm_MST_Branch].[BranchCode]
WHERE Date between #FDM and DATEADD(day,0, CAST(GETDATE() AS date)) and {{select_Laboratory}} and LAB.dbo.[LAB_TRN_BillHeader].[IsVoid] = '0' and LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode] in ('URCR022','MRPMC','KUCC','KOCC','EHECC')
GROUP BY LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode], LAB.dbo.[LAB_Comm_MST_CollectingCenter].[Name], LAB.dbo.[LAB_Comm_MST_Branch].[BranchName]
Current Result:
|Total_Sale|CollectingCenterCode|Name|BranchName|
|xxx |xxx |x |xx |
Required Result:
|Total_Sale|Total_Sale2|CollectingCenterCode|Name|BranchName|
|xxx |xxx |xx |x |xx |
Total_Sale = Sale of current month up to yesterday
Total_Sale2 = Sale of Last month up to current month's yesterday's date.
-- MSSQL Version - 2014
-- <Create_Date> is a time stamp in the table in <Create_Date> column. The date/time is obtained from that timestamp. Each transaction is saved with a respective timestamp at it's time of occurrence.
-- {{select_Laboratory}} is a field filter alias in Metabase (this code was copied from a Metabase dashboard). The actual code is LAB.dbo.[LAB_TRN_BillHeader].[BranchCode] = '001'
Considering a sales CreateDate is likely of type Datetime or Datetime2, a safe approach would be:
DECLARE #yesterday DATE = GETDATE();
DECLARE #lastMonth DATE = DATEADD(MONTH, -1, #yesterday);
DECLARE #firstDayOfThisMonth DATE = DATEADD(DAY, 1 - DAY(#yesterday), #yesterday);
DECLARE #firstDayOfLastMonth DATE = DATEADD(DAY, 1 - DAY(#lastMonth), #lastMonth);
SELECT #yesterday,
#firstDayOfThisMonth,
#lastMonth,
#firstDayOfLastMonth;
SELECT [locationId],
SUM( CASE
WHEN CreateDate >= #firstDayOfThisMonth
AND CreateDate < #yesterday THEN
AmountToBePaid
END
) AS Sum_of_Sale_1,
SUM( CASE
WHEN CreateDate >= #firstDayOfLastMonth
AND CreateDate < #lastMonth THEN
AmountToBePaid
END
) AS Sum_of_Sale_2
FROM BillHeader
GROUP BY [locationId];
EDIT: Note that in dates like March 31,30 previous month's end date could be Feb 28, 29.
You could use conditional aggregation with the following date functions:
DATEADD(Day, 1, EOMONTH(GETDATE(), -1)) gets the first date of the current month, i.e. current month is Jan-2023 it will return '2023-01-01'.
CAST(GETDATE() AS DATE) gets today's date.
DATEADD(Day, 1, EOMONTH(GETDATE(), -2)) gets the first date of the previous month, i.e. current month is Jan-2023 it will return '2022-12-01'.
DATEADD(Month, -1, CAST(GETDATE() AS DATE) gets the date of the day one-month pre today's date.
SELECT Location,
SUM(CASE
WHEN CreateDate >= DATEADD(Day, 1, EOMONTH(GETDATE(), -1)) AND
CreateDate < CAST(GETDATE() AS DATE)
THEN Sales END) Sum_of_Sale_1,
SUM(CASE
WHEN CreateDate >= DATEADD(Day, 1 ,EOMONTH(GETDATE(), -2)) AND
CreateDate < DATEADD(Month, -1, CAST(GETDATE() AS DATE))
THEN Sales END) Sum_of_Sale_2
FROM BillHeader
GROUP BY Location
See demo
There are different ways of doing the calculations and I don't know if this logic will seem more straightforward or as concise. Also you might not be able to use variables. Lastly, you didn't specify which version you're running.
Although you can incorporate this into an existing query that covers a wider range of dates, here is a stand-alone option that should restrict the execution to a narrower range of dates. The case logic, as written, does assume that rows have already been filtered so the only thing left to determine is whether the sale comes from current month or prior month.
select Location,
sum(case when month(CreateDate) <> month(getdate()) then Sales end) as Sales1,
sum(case when month(CreateDate) = month(getdate()) then Sales end) as Sales2
from BillHeader
where
-- go back enough days to guarantee covering last two months
-- this may be able to utilize an index
SalesDate between dateadd(day, -30 - day(getdate()), cast(getdate() as date))
and getdate()
-- now eliminate extra dates that are not relevant
and month(getdate()) - month(CreateDate) in (0, 1, -11) /* year might roll over */
and day(getdate()) > day(CreateDate)
group by Location;
For a YOY comparison over the same calendar month:
select Location,
sum(case when year(CreateDate) <> year(getdate()) then Sales end) as Sales1,
sum(case when year(CreateDate) = year(getdate()) then Sales end) as Sales2
from BillHeader
where
-- go back enough days to guarantee covering last 13 months
-- (or rewind as 396 days via parallel logic from earlier)
SalesDate between
dateadd(year, -1, dateadd(day, 1 - day(getdate()), cast(getdate() as date)))
and getdate()
and month(getdate()) = month(CreateDate)
and day(getdate()) > day(CreateDate)
group by Location;
This might be better done as a union with two different date ranges combined together:
-- ...
where
SalesDate between
dateadd(year, -1, dateadd(day, 1 - day(getdate()), cast(getdate() as date)))
and dateadd(year, -1, getdate())
-- ... union all ...
where
SalesDate between
dateadd(day, 1 - day(getdate()), cast(getdate() as date))
and getdate()
-- ...

SQL Server Group a promotion by last 24 hours, last week and last month and sort by week descending

I'm trying to look at how successful different promotions have been in the last 24 hours, week and month. To get the amount by promotion for the last 24 hours I've used this code but I don't understand how to get another two columns for the last week and the last month. And then finally I want to order it by the amount in the last week descending. I want to be able to run this query at any point during the month. Please help me.
SELECT Promotion
, Sum(Amount) AS Last_24
FROM dbo.CustomerPayment
WHERE Started >= DATEADD(day, - 1, GETDATE())
GROUP
BY Promotion
You can do it in a single query :
SELECT Promotion
, Sum(CASE WHEN Started >= DATEADD(day, -1, GETDATE()) THEN Amount ELSE 0 END) AS Last_24
, Sum(CASE WHEN Started >= DATEADD(day, -7, GETDATE()) THEN Amount ELSE 0 END) AS Last_Week
, Sum(Amount) AS Last_Month
FROM dbo.CustomerPayment
WHERE Started >= DATEADD(day, - 31, GETDATE())
GROUP
BY Promotion
ORDER BY Last_Week DESC
Note that this part :
WHERE Started >= DATEADD(day, - 31, GETDATE())
as te be clarified following your own interpretation of "Last Month" concept.
Use conditional aggregation -- that is, move the conditions to the select:
SELECT Promotion,
SUM(case when Started >= DATEADD(day, - 1, GETDATE()) then Amount end) AS Last_1_day,
SUM(case when Started >= DATEADD(day, - 7, GETDATE()) then Amount end) AS Last_7_day,
. . .
FROM dbo.CustomerPayment
GROUP BY Promotion;
One possible issue, though. GETDATE() -- despite its name -- returns a time component to the date. I suspect that you might actually want to treat this as a date, not a datetime:
SELECT Promotion,
SUM(case when Started >= DATEADD(day, - 1, CONVERT(DATE, GETDATE())) then Amount end) AS Last_1_day,
SUM(case when Started >= DATEADD(day, - 7, CONVERT(DATE, GETDATE())) then Amount end) AS Last_7_day,
. . .
FROM dbo.CustomerPayment
GROUP BY Promotion;
I was looking for month / week. Not 7 / 30 days.
If you wish those, just use variables to have that query readable.
declare #monthstart date,
#weekstart date
;
select #monthstart=datefromparts(year(current_timestamp),month(current_timestamp),1)
select cast(DATEADD(d,1-DATEPART(WEEKDAY,current_timestamp),CURRENT_TIMESTAMP) as date) as Sunday,
cast(DATEADD(d,2-case when DATEPART(WEEKDAY,current_timestamp)=1 then 8 else DATEPART(WEEKDAY,current_timestamp) end,CURRENT_TIMESTAMP) as date) as Monday
;

Current Year To Date, Last Year To Date, and Other

I need to classify a set of dates as either 'Cur. YTD', 'Lst. YTD', or 'Other'. YTD is based upon getdate(). I have a temp table for testing that has a single column called 'calendar_date' of type DATETIME. I came up with this logic and it appears to work. I'm just wondering if this approach makes good sense from a performance perspective or if something else might be better.
select calendar_date,
case when (MONTH(calendar_date) < MONTH(getdate()))
or (MONTH(calendar_date) = MONTH (getdate())
AND DAY(calendar_date) <= DAY(getdate())) then
case when YEAR(calendar_date) = YEAR(GETDATE()) then 'CYTD'
when YEAR(calendar_date) = YEAR(getdate()) - 1 then 'LYTD'
else 'Other'
end
else 'Other'
end as Tim_Tag_YTD
from #temp1
Your logic looks good and will work as-is.
An alternative which simplifies a little, which assumes you have no future data.
select
calendar_date,
Tim_Tag_YTD = case DATEDIFF(YEAR, calendar_date, GETDATE())
when 0 then 'CYTD'
when 1 then 'LYTD'
else 'Other'
end
from #temp1;
In the case of your logic, you are explicitly putting future data into 'Other', which you can also do like this:
select
calendar_date,
Tim_Tag_YTD = case when calendar_date > GETDATE() then 'Other' else
case DATEDIFF(YEAR, calendar_date, GETDATE())
when 0 then 'CYTD'
when 1 then 'LYTD'
else 'Other'
end
end
from #temp1;
Sometimes something unintuitive performs faster. Something like this might be worth a shot.
set variable #FirstOfLastYear to Jan 1 of last year
using sql server date functions
set #FirstOfThisYear = DateAdd(year, 1, #FirstOfLastYear)
select 'last year' period
, whatever else you need
from #temp1 where calendar_date >= #FirstOfLastYear
and calendar_date < #FirstOfThisYear
union
select 'this year' period
, whatever else you need
from #temp1 where calendar_date >= #FirstOfThisYear
and calendar_date < getDate ()
union
select 'other' period
, whatever else you need
from #temp1 where calendar_date <= #FirstOfLastYear
or calendar_date > getdate()
You'll never know unless you try.

How do I search and group by a date column into sets of duration ranges?

I have a table like this;
jobID - jobTitle - jobCreatedDate
I want to make it possible for visitors to search in Jobs table and list it by grouping like this and I want to do it with just one SQL query:
Date Added
- AnyTime (20)
- 1 day ago (5)
- 2-7 days ago (2)
- 8-14 days ago (0)
- 15-30 days ago (7)
I tried Group By "jobCreatedDate" with no success and I couldn't understand the logic of the necessary query.
Here is an example what I'm trying to do:
Thanks for help.
You need to find the date difference between today and the field JobCreated. Then based on the difference in the value days, you need to classify the output accordingly into various categories to meet your requirements.
I hope that is what you are looking for.
SELECT SUM(1) AS [AnyTime]
, SUM(CASE WHEN DayCount = 1 THEN 1 ELSE 0 END) AS [1 day ago]
, SUM(CASE WHEN DayCount BETWEEN 2 AND 7 THEN 1 ELSE 0 END) AS [2-7 days ago]
, SUM(CASE WHEN DayCount BETWEEN 8 AND 14 THEN 1 ELSE 0 END) AS [8-14 days ago]
, SUM(CASE WHEN DayCount BETWEEN 15 AND 30 THEN 1 ELSE 0 END) AS [15-30 days ago]
FROM
(
SELECT JobID
, DATEDIFF(d, JobCreatedDate, GETDATE()) AS DayCount
FROM dbo.Jobs
) Jobs
Screenshot shows sample data and the query output.
Use the DATEADD tsql method.
Select ...
From [Table]
Where JobCreatedDate between DATEADD(dd, #NumDays, GetDate()) and GetDate()
In this query #NumDays is a parameter representing the number of days to subtract from the current date. Make sure you pass a negative number to the query. If you are trying to create non inclusive ranges, you'll need to use two DATEADD calls passing two parameters to the query.
EDIT
I misunderstood what you were trying to do. This may not be the most elegant solution, but you could accomplish your goal using a union query.
Select sum(OneDay) as OneDay, sum(SevenDays) as SevenDays
From
(select 1 as OneDay, 0 as SevenDays
From [table]
Where JobCreatedDate between DATEADD(dd, -1, GetDate()) and GetDate())
UNION
(select 0 as OneDay, 1 as SevenDays
From[table]
Where JobCreatedDate between DATEADD(dd, -7, GetDate()) and DATEADD(dd, -2, GetDate()))

SQL trend over time

I have a table with two columns, date and score. I want to find something like:
Sum as of 7 days ago
Sum as of 6 days ago
...
Sum as of today
An individual thing could be found with
select sum(score) from my_table
where date <= DateAdd("d", -1, getdate)
But I would like to not have to run a new query every time.
(I am using django, but pure SQL solutions are fine too.)
Use case statements to sum each value you care about.
SELECT
(CASE WHEN date <= DateAdd("d", -1, getdate) THEN score ELSE 0 END) as sum1,
(CASE WHEN date <= DateAdd("d", -2, getdate) THEN score ELSE 0 END) as sum2, etc.