SQL - create multiple calendars in one table - sql

I am trying to create a table which calculates multiple calendars depending on the start and end date of a certain row. I have a table which looks like this:
key Start_date End_date
123.1 1-10-2009 24-12-2009
123.2 1-7-2010 9-2-2011
123.3 1-5-2011 30-10-2011
.........
For each key I want a new row with startdate +1 month until enddate.
For now I have query which works only if my temporary table contains one row, which is:
DECLARE #StartDate DATE = (select Start_date from #dim2);
SET DATEFIRST 7;
SET DATEFORMAT ymd;
SET LANGUAGE US_ENGLISH;
DECLARE #CutoffDate DATE = (select End_date from #dim2);
CREATE TABLE #dim3
([verwachte_aflossing] DATE,-- PRIMARY KEY,
);
INSERT #dim3([verwachte_aflossing] )
SELECT d
FROM
(
SELECT d = DATEADD(month, rn-1, #StartDate)
FROM
(
SELECT TOP (DATEDIFF(month, #StartDate, #CutoffDate))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]
) AS x
) AS y
Does anyone now how to handle this?

For SQL Server recursive cte is one option to do that
WITH CTE as
(
select [Key], start_date, end_date from table
union all
select [Key], dateadd(month,1,start_date) start_date, end_date
from cte
where datediff(month, start_date, end_date) > 0
)
SELECT * FROM CTE
OPTION (MAXRECURSION 0)

Related

I want to create table or view from a recursion used to generate a date in ssms

I wrote a recursive query to generate a column pf dates. I want the dates to be stored as a table in a db but can't seem to find a way.
declare #startdate date = '2014-01-01';
declare #enddate date = '2023-12-31';
with calendar as
(
select #startdate as [orderDate]
union all
select DATEADD(dd,1,[orderdate])
from calendar
where DATEADD(dd,1,[orderdate])<= #enddate
)
select * from calendar
option (maxrecursion 0);
you can try this one to fill a new table your_table with the dates.
You can use that as a basis for your further operations.
WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
select
convert(date, dat ) Dat
into your_table
from
(
SELECT top 100 percent
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) Line,
dateadd(day, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), '2014-01-01') Dat
FROM x ones, x tens, x hundreds, x thousands
ORDER BY 1
) basis
where dat <= '2023-12-31'

Generate data between two range date by some values

I have 2 dates, StartDate and EndDate:
Declare #StartDate date='2018/01/01', #Enddate date ='2018/12/31'
Then there is some data with a date and value in a mytable table:
----------------------------
ID date value
----------------------------
1 2018/02/14 4
2 2018/09/26 7
3 2017/09/20 2
data maybe start before 2018 and if it exist before #startdate get before values
else get 0
I'm looking to get a result that looks like this:
-----------------------------------
fromdate todate value
-----------------------------------
2018/01/01 2018/02/13 2
2018/02/14 2018/09/25 4
2018/09/26 2018/12/31 7
The first fromdate comes from #StartDate and the last todate is from #Enddate, and the other data should be generated.
I'm hoping to get this in an SQL query. I use sql-server 2016
You could use a CTE to create your full range of dates, and then LEAD to create the ToDate column:
DECLARE #FromDate date = '20180101',
#ToDate date = '20181231';
WITH VTE AS(
SELECT ID,
CONVERT(date,[date]) [date], --This is why using keywords for column names is a bad idea
[value]
FROM (VALUES(1,'20180214',4),
(2,'20180926',7),
(3,'20170314',4))V(ID,[date],[value])),
Dates AS(
SELECT [date]
FROM VTE V
WHERE V.[date] BETWEEN #FromDate and #ToDate
UNION ALL
SELECT [date]
FROM (VALUES(#FromDate))V([date]))
SELECT D.[date] AS FromDate,
LEAD(DATEADD(DAY, -1,D.[date]),1,#ToDate) OVER (ORDER BY D.[date]) AS ToDate,
ISNULL(V.[value],0) AS [value]
FROM Dates D
LEFT JOIN VTE V ON D.[date] = V.[date];
db<>fiddle
with cte as
(
select 0 as row_num, #StartDate as start_date, 0 as val
UNION
select ROW_NUMBER() OVER(ORDER BY start_date) as row_num, * from input
)
select curr.start_date
, DATEADD(day,-1,ISNULL(nex.start_date,DATEADD(day,1,#Enddate))) as end_date
, curr.val
from cte curr
left join cte nex on curr.row_num = nex.row_num - 1;
You can find the simulation here: https://rextester.com/EIAXW23839

SQL Cross Join getting all dates between date range

I have a table with the following structure:
ID: StartDate: EndDate
I want to show all dates in the date range for each ID.
Eg
ID = 1: StartDate = 01/01/2018: EndDate = 03/01/2018
ID: 1 01/01/2018
ID: 1 02/01/2018
ID: 1 03/01/2018
I think i need to use a cross join but im unsure how to create this for multiple rows?
Here is the CTE for SQL Server, the syntax is somewhat different:
declare #startdate date = '2018-01-01';
declare #enddate date = '2018-03-18';
with
dates as (
select #startdate as [date]
union all
select dateadd(dd, 1, [date]) from dates where [date] < #enddate
)
select [date] from dates
So i ended up using a date table and just cross referencing that
select *
from Date d
inner join WorkingTable w
on d.Date >= w.StartDate
and d.date < w.EndDate
In standard SQL you can use a recursive CTE:
with recursive dates as (
select date '2018-01-01' as dte
union all
select dte + interval '1 day'
from dates
where dte < date '2018-01-03'
)
select dte
from dates;
The exact syntax (whether recursive is needed and date functions) differ among databases. Not all databases support this standard functionality.
Now got this for only one id..,
create table #dateTable(id int, col1 date, col2 date)
insert into #dateTable values(1,'05-May-2018','08-May-2018') ,(2,'05-May-2018','05-May-2018')
select *from #dateTable
with cte(start, ends) as(
select start = (select top 1 col1 from #dateTable), ends = (select top 1 col2 from #dateTable)
union all
select DATEADD(dd,1,start),ends from cte where start <> ends
)select start from cte option (maxrecursion 10)
I'm still working... I update soon...!

Find missing date as compare to calendar

I am explain problem in short.
select distinct DATE from #Table where DATE >='2016-01-01'
Output :
Date
2016-11-23
2016-11-22
2016-11-21
2016-11-19
2016-11-18
Now i need to find out missing date a compare to our calender dates from year '2016'
i.e. Here date '2016-11-20' is missing.
I want list of missing dates.
Thanks for reading this. Have nice day.
You need to generate dates and you have to find missing ones. Below with recursive cte i have done it
;WITH CTE AS
(
SELECT CONVERT(DATE,'2016-01-01') AS DATE1
UNION ALL
SELECT DATEADD(DD,1,DATE1) FROM CTE WHERE DATE1<'2016-12-31'
)
SELECT DATE1 MISSING_ONE FROM CTE
EXCEPT
SELECT * FROM #TABLE1
option(maxrecursion 0)
Using CTE and get all dates in CTE table then compare with your table.
CREATE TABLE #yourTable(_Values DATE)
INSERT INTO #yourTable(_Values)
SELECT '2016-11-23' UNION ALL
SELECT '2016-11-22' UNION ALL
SELECT '2016-11-21' UNION ALL
SELECT '2016-11-19' UNION ALL
SELECT '2016-11-18'
DECLARE #DATE DATE = '2016-11-01'
;WITH CTEYear (_Date) AS
(
SELECT #DATE
UNION ALL
SELECT DATEADD(DAY,1,_Date)
FROM CTEYear
WHERE _Date < EOMONTH(#DATE,0)
)
SELECT * FROM CTEYear
WHERE NOT EXISTS(SELECT 1 FROM #yourTable WHERE _Date = _Values)
OPTION(maxrecursion 0)
You need to generate the dates and then find the missing ones. A recursive CTE is one way to generate a handful of dates. Another way is to use master..spt_values as a list of numbers:
with n as (
select row_number() over (order by (select null)) - 1 as n
from master..spt_values
),
d as (
select dateadd(day, n.n, cast('2016-01-01' as date)) as dte
from n
where n <= 365
)
select d.date
from d left join
#table t
on d.dte = t.date
where t.date is null;
If you are happy enough with ranges of missing dates, you don't need a list of dates at all:
select date, (datediff(day, date, next_date) - 1) as num_missing
from (select t.*, lead(t.date) over (order by t.date) as next_date
from #table t
where t.date >= '2016-01-01'
) t
where next_date <> dateadd(day, 1, date);

How can I sum values per day and then plot them on calendar from start date to last date

I have a table, part of which is given below. It contain multiple values (durations) per day. I need two things 1) addition of durations per day. 2) plotting them on calendar in such a way that startdate is first_date from the table and last_date is Last_update from the table. I want to mention 0 for which date there is no duration. I think it will something like below but need help.
;WITH AllDates AS(
SELECT #Fromdate As TheDate
UNION ALL
SELECT TheDate + 1
FROM AllDates
WHERE TheDate + 1 <= #ToDate
)SELECT UserId,
TheDate,
COALESCE(
SUM(
-- When the game starts and ends in the same date
CASE WHEN DATEDIFF(DAY, GameStartTime, GameEndTime) = 0
Here is what I am looking for
Another way to generate the date range you are after would be something like .....
;WITH DateLimits AS
(
SELECT MIN(First_Date) FirstDate
,MAX(Last_Update) LastDate
FROM TableName
),
DateRange AS
(
SELECT TOP (SELECT DATEDIFF(DAY,FirstDate,LastDate ) FROM DateLimits)
DATEADD(DAY
,ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
, (SELECT FirstDate FROM DateLimits)
) AS Dates
FROM master..spt_values a cross join master..spt_values b
)
SELECT * FROM DateRange --<-- you have the desired date range here
-- other query whatever you need.