Rolling 3 Years of data with desired format - sql-server

Start Date = 2016-03-01
End Date = 2019-02-15
I need the query/Function which should retrive the below result based on start and end date. I have a query to frame the result .But i need some query/function to retrive result set in 5 to 10 sec with performance

You mean like
SELECT * FROM table WHERE [start date]>='2016-03-01' AND [end date]<='2019-02-15'
Am I missing something? This seems too simple to ask as a question
If your problem is performance perhaps consider indexing start and end date columns, and if you're only getting a couple other values from the table include those in the index too.
CREATE INDEX IX_table_startdate_enddate
ON schema.table ([start date], [end date])
INCLUDE (othercolumn1, othercolumn2);
It means that queries like:
SELECT othercolumn1, othercolumn2 FROM table
WHERE [start date]>='2016-03-01' AND [end date]<='2019-02-15'
Can be answered from the index without having to connect the index to the table to pull the desired data
If you still can't wrong enough out of it after that perhaps you have a design flaw in your app; pilling a db for a massive amount of data in a tight interval could be solved another way like only emitting events when data actually changes

It's just occurred to me you're probably looking for a query to generate that result set from nothing. In sqlserver we can use a recursive cte:
DECLARE #dateFrom DATE = '2016-03-01'
DECLARE #dateTo DATE = '2019-02-15'
with d as (
SELECT #datefrom as m
UNION ALL
SELECT DATEADD(MONTH,1,reqDate)
FROM d
WHERE DATEADD(MONTH,1,reqDate) <= #dateto
),
SELECT
CONCAT(
DATENAME(MONTH, #dateFrom), ' ',
CASE WHEN MONTH(d.m) < MONTH(#dateFrom) THEN YEAR(d.m) - 1 ELSE YEAR(d.m) END, '-',
DATENAME(MONTH, #dateTo), ' ',
CASE WHEN MONTH(d.m) < MONTH(#dateFrom) THEN YEAR(d.m) ELSE YEAR(d.m) +1 END
) as range,
MONTH(d.m) as month,
d.m as startdate,--do not use spaces in column names
CASE WHEN #dateTo < EOMONTH(d.m) then #dateTo ELSE EOMONTH(d.m) END as enddate --or dateadd 1 month then dateadd -1 day if you don't have eomonth
FROM d
OPTION(MAXRECURSION 0);

Same format with your result try it.
DECLARE #StartDate DATETIME, #EndDate DATETIME
SET #StartDate = '2016-03-01'
SET #EndDate = '2038-02-15'
;WITH CTEs AS
(
SELECT #StartDate as [Start Date]
UNION ALL
SELECT DATEADD(MONTH,1,[Start Date])
FROM CTEs WHERE DATEADD(MONTH,1,[Start Date]) <= #EndDate
)
SELECT
CONCAT(
DATENAME(MONTH, #StartDate), ' ',
CASE WHEN MONTH([Start Date]) < MONTH(#StartDate) THEN YEAR([Start Date]) - 1 ELSE YEAR([Start Date]) END, '-',
DATENAME(MONTH, #EndDate), ' ',
CASE WHEN MONTH([Start Date]) < MONTH(#StartDate) THEN YEAR([Start Date]) ELSE YEAR([Start Date]) + 1 END
) AS [Range],
MONTH([Start Date]) AS [Month],
CONVERT(VARCHAR(10),[Start Date],101) AS [Start Date],
CONVERT(VARCHAR(10),(CASE WHEN [Start Date] <> DATEFROMPARTS(YEAR(#EndDate),MONTH(#EndDate),1)
THEN EOMONTH([Start Date])
ELSE #EndDate
END),101) AS [End Date]
FROM CTEs
OPTION(MAXRECURSION 0);

Related

How to get Satuday's date of previous month in SQL Server? Can someone help me with this query?

Suppose now we are in September, I want output of the last Saturday date in the previous month, August, where 28-08-2021 falls under last Saturday of previous month in SQL Server
..fiddle..
select *, datename(weekday, pmlsat), dateadd(week, 1, pmlsat)
from
(
select _date,
--last saturday of previous month
dateadd(day, -datepart(weekday, dateadd(day, ##datefirst, eomonth(_date, -1)))%7, eomonth(_date, -1)) as pmlsat
from
(
select top(100) dateadd(month, row_number() over(order by ##spid), '20141215') as _date
from sys.all_objects
) as d
) as p
order by _date;
DECLARE #date1 DATETIME
SET #date1='2021-8-31'
WHILE Day(#date1) >= 1
BEGIN
IF (SELECT Datename(weekday, #date1)) = 'Saturday'
BREAK
SET #date1=Dateadd(dd, -1, #date1)
CONTINUE
END
SELECT Datename(weekday, #date1) AS 'Datename',
(SELECT CONVERT(NVARCHAR(20), #date1, 23)) AS 'DATE'
First, let's talk about how to get the beginning of this month. There are a multiple ways, I find DATEFROMPARTS() the most intuitive (see Simplify Date Period Calculations in SQL Server):
DECLARE #FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT #FirstOfMonth;
-- result:
-- 2021-09-01
Now, the last Saturday in the previous month must be between 1 and 7 days before the first of this month. So we can generate a sequence of 7 consecutive numbers, and subtract those days from the first of the month, like this:
DECLARE #FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT #FirstOfMonth;
;WITH n(n) AS
(
SELECT 1 UNION ALL
SELECT n + 1 FROM n WHERE n < 7
)
SELECT d = DATEADD(DAY, -n, #FirstOfMonth) FROM n;
/* result:
2021-08-31
2021-08-30
2021-08-29
2021-08-28
2021-08-27
2021-08-26
2021-08-25 */
To determine what a Saturday is, you either need to rely on DATEPART(WEEKDAY, date) - which in turn is affected by SET DATEFIRST, or you need to rely on DATENAME(WEEKDAY, date) - which in turn is affected by SET LANGUAGE. I will err toward language being more stable (English), so:
DECLARE #FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT #FirstOfMonth;
;WITH n(n) AS
(
SELECT 1 UNION ALL
SELECT n + 1 FROM n WHERE n < 7
),
d(d) AS
(
SELECT DATEADD(DAY, -n, #FirstOfMonth)
FROM n
)
SELECT LastMonthLastSaturday = d
FROM d
WHERE DATENAME(WEEKDAY, d) = 'Saturday';
-- result:
-- 2021-08-28
But that is a subjective call - if you can't rely on one of those, get a calendar table, then it's simply something like:
SELECT LastMonthLastSaturday = MAX(TheDate)
FROM dbo.Calendar
WHERE TheDayOfWeekName = 'Saturday'
AND TheDate < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);

SSRS 2017 Cascading parameters with dates

I have a parameter called Year and you can choose one year at a time. I have a date/time parameter with a calendar called start date and another one called end date.
I would like it to work such that if I pick the year to be 2017 it will show the calendar start and end dates for 2017.
Since my start date and end date parameters are not defaulted from a dataset I am not sure how to control that.
Any help will be appreciated.
You can do it as an expression, but as its easier in SQL you can just create a second dataset with the following:
select convert(date, '1 jan ' + convert(varchar(4), #Year)), dateadd(day, -1, dateadd(year, 1, convert(date, '1 jan ' + convert(varchar(4), #Year))))
I used a recursive CTE common table expression that references itself to solve this. Then you can set the Dataset of the start_date and end_date parameters.
Dataset for the default values of the start and end date parameters
DECLARE #year AS INT
SET #year = 2018
SELECT [start_date] = DATEFROMPARTS(#year, 1, 1), [end_date] = DATEFROMPARTS(#year, 12, 31)
Dataset for the available values of the start and end date parameters
DECLARE #year AS INT
SET #year = 2018
;WITH
source_data_dates
AS
(
SELECT
[date_start] = DATEFROMPARTS(#year, 1, 1)
, [date_end] = DATEFROMPARTS(#year, 12, 31)
)
,
year_date_list([rn], [date_value])
AS
(
SELECT
[rn] = 1
, [date_value] = CAST([date_start] AS DATETIME)
FROM
source_data_dates
UNION ALL
SELECT
[rn] = [rn] + 1
, [date_start] = CAST(DATEADD(DAY, [rn], [date_start]) AS DATETIME)
FROM
year_date_list
, source_data_dates
WHERE
[rn] <= DATEDIFF(DAY, [date_start], [date_end])
)
SELECT
[rn]
, [date_value]
FROM
year_date_list
OPTION (MAXRECURSION 0)
Results:

(MS SQL Server) Setting Case Statement Column Name With A Formula

I would like to use a formula to set column names for case statements but the straightforward approach is not accepted. Here is the example of what I am attempting to do - is there a way to make this work?
select
ID
-- Pull DeDupe_Decision_Count for that ID last month (EOM_Date), where each ID has multiple rows in the data set for each data month
, sum(case when EOM_Date = CONVERT(DATE, DATEADD(s,-1,DATEADD(m,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))))
then DeDupe_Decision_Count end)
as CONVERT(DATE, DATEADD(s,-1,DATEADD(m,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))))
-- Pulling the same for two months ago
, sum(case when EOM_Date = CONVERT(DATE, DATEADD(s,-1,DATEADD(m,-2,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))))
then DeDupe_Decision_Count end)
as CONVERT(DATE, DATEADD(s,-2,DATEADD(m,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))))
-- Pulling the same for three months ago
, sum(case when EOM_Date = CONVERT(DATE, DATEADD(s,-1,DATEADD(m,-3,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))))
then DeDupe_Decision_Count end)
as CONVERT(DATE, DATEADD(s,-2,DATEADD(m,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))))
-- Would like to do the same for 12-24 months
from Mytable
group by ID
I would like to use the formula instead of a static date because this will be updated monthly and include 12-24 months of data. I could use variables and just name the columns last month, 2 months ago, 3 months ago, etc. but I would rather the column name be the date of the month.
This requires dynamic query
DECLARE #sql VARCHAR(max)
SET #sql = 'select
case
when EOM_Date = CONVERT(DATE, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)))
then ''DeDupe_Decision_Count''
end as '+ Quotename(CONVERT(DATE, Dateadd(s, -1, Dateadd(mm, Datediff(m, 0, Getdate()), 0))))
PRINT #sql
exec(#sql)

TSQL get last day of previous months upto a specified month

I need to get last day of all previous months including current month, upto a specified month. For example, I need last days of september, aug, july, june, may, april, march, feb, jan, dec 2015 like so:
temptable_mytable:
last_day_of_month
-----------------
2016-09-30
2016-08-31
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2016-03-31
2016-02-30
2016-01-31
2015-12-31
I need to specify the month and year to go back to - in above case it's December 2015, but it could also be September 2015 and such. Is there a way that I can do a loop and do this instead of having to calculate separately for each month end?
Use a recursive CTE with the EOMONTH function.
DECLARE #startdate DATE = '2016-01-01'
;WITH CTE
AS
(
SELECT EOMONTH(GETDATE()) as 'Dates'
UNION ALL
SELECT EOMONTH(DATEADD(MONTH, -1, [Dates]))
FROM CTE WHERE Dates > DATEADD(MONTH, 1, #startdate)
)
SELECT * FROM CTE
with temp as (select -1 i union all
select i+1 i from temp where i < 8)
select DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+i*-1,0)) from temp
declare #LASTMONTH date = '2018-10-01';
WITH MTHS AS (
SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday
UNION ALL
SELECT DATEADD(month,1,aday) from MTHS WHERE aday <= #LASTMONTH
),
LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)
select * from LASTDAYS
Here is a version that goes forward or backwards as appropriate
declare #LASTMONTH date = '2013-10-01';
WITH DIF AS (SELECT CASE WHEN
YEAR(#LASTMONTH) * 12 + MONTH(#LASTMONTH)
>= YEAR(GETDATE()) * 12 + MONTH(getdate()) THEN 1 ELSE -1 END x),
MTHS AS (
SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday
UNION ALL
SELECT DATEADD(month,(SELECT X from dif),aday) from MTHS
WHERE month(aday) != month(dateadd(month,1,#LASTMONTH)) or YEAR(aday) != YEAR(dateadd(month,1,#LASTMONTH))
),
LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)
select * from LASTDAYS order by finaldayofmonth
Here's one approach, using a CTE to generate a list of incrementing numbers to allow us to then have something to select from and use in a DATEADD to go back for the appropriate number of months.
Typically, if you're doing this quite frequently, instead of generating numbers on the fly like this with the CROSS JOIN, I'd recommend just creating a "Numbers" table that just holds numbers from 1 to "some number high enough to meet your needs"
DECLARE #Date DATE = '20151201'
DECLARE #MonthsBackToGo INTEGER
SELECT #MonthsBackToGo = DATEDIFF(mm, #Date, GETDATE()) + 1;
WITH _Numbers AS
(
SELECT TOP (#MonthsBackToGo) ROW_NUMBER() OVER (ORDER BY o.object_id) AS Number
FROM sys.objects o
CROSS JOIN sys.objects o2
)
SELECT EOMONTH(DATEADD(mm, -(Number- 1), GETDATE())) AS last_day_of_month
FROM _Numbers
This should scale out no matter how far you go back or forward for your originating table or object.
SET NOCOUNT ON;
DECLARE #Dates TABLE ( dt DATE)
DECLARE #Start DATE = DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
DECLARE #End DATE = DATEADD(YEAR, 1, #Start)
WHILE #Start <= #End
BEGIN
INSERT INTO #Dates (dt) VALUES (#Start)
SELECT #Start = DATEADD(DAY, 1, #Start)
END
; With x as
(
Select
dt
, ROW_NUMBER() OVER(PARTITION BY DATEPART(YEAR, Dt), DATEPART(MONTH, Dt) ORDER BY Dt Desc) AS rwn
From #Dates
)
Select *
From x
WHERE rwn = 1
ORDER BY Dt
This was cribbed together quick based on a couple different SO answers for the parts:
DECLARE #startdate datetime, #enddate datetime
set #startdate = '2015-12-01'
set #enddate = getdate()
;WITH T(date)
AS
(
SELECT #startdate
UNION ALL
SELECT DateAdd(day,1,T.date) FROM T WHERE T.date < #enddate
)
SELECT DISTINCT
DATEADD(
day,
-1,
CAST(CAST(YEAR(date) AS varchar) + '-' + CAST(MONTH(date)AS varchar) + '-01' AS DATETIME))
FROM T OPTION (MAXRECURSION 32767);

SQL Server group by / count issue

I'm trying to count Holiday bookings (B.ID) for dates 2 days either side of today.
It works but my results are separated as I have to introduce the end date of
the holiday too, which varies for each start date (holidays have different durations).
The separates out my counts. What I need is one count for each date. Is there a way of working round this? I kinda just want to exclude the vwReturnDate from the group by but have to put it there as I've used it in my count.
In English I want - For each [date] count the number of [B.id] where [B.Depart] <= [date] and [vwReturnDate] > [date]
DECLARE #startDate DATE
DECLARE #endDate DATE
SET #startDate = Getdate()-2
SET #endDate = Getdate()+2;
WITH dates(Date) AS
( SELECT #startdate as Date
UNION ALL
SELECT DATEADD(d,1,[Date])
FROM dates
WHERE DATE < #enddate )
SELECT
[Date] as 'Calendar Date',
--CONVERT(VARCHAR(10), [Date],103) AS 'Date'
-- ,CONVERT(CHAR(2), [Date], 113) AS 'Day'
-- ,CONVERT(CHAR(4), [Date], 100) AS 'Month'
-- ,CONVERT(CHAR(4), [Date], 120) AS 'Year',
Case when B.Depart <= [date] AND vwR.ReturnDate >=[date] then count (B.ID) end AS 'Number of holidays live on date'
FROM [dates]
left join Booking B on B.depart=[Date]
inner join Quote Q on Q.ID=B.QuoteID
inner join vwReturnDate vwR on vwR.ID=B.ID
Group by [date], B.depart, vwR.ReturnDate
order by [date]
OPTION (MAXRECURSION 0)
GO

Resources