How to repeat the values between the two dates? - sql

Using SQL Server 2005
I want to generate the table values between the two dates
Table1
ID Date Intime Outtime
01 12-02-2009 10:00:00 17:00:00
02 13-02-2009 08:00:00 16:00:00
03 14-02-2009 09:00:00 21:00:00
04 15-02-2009
Suppose I want to generate the above table values between the two dates.
For Example,
Given Date: start date - 12-02-2009 to end date - 12-03-2009
Expected Output,
ID Date Intime Outtime
01 12-02-2009 10:00:00 17:00:00
02 13-02-2009 08:00:00 16:00:00
03 14-02-2009 09:00:00 21:00:00
04 15-02-2009
05 16-02-2009 10:00:00 17:00:00
06 17-02-2009 08:00:00 16:00:00
07 18-02-2009 09:00:00 21:00:00
08 19-02-2009
09 20-02-2009 10:00:00 17:00:00
…,
So From table1 we have 4 Rows, so the 4 rows will repeat up to the given end date but id and date should increment, id and date should not repeat.
How to make a SQL Query for this condition?
Need Query Help.

Try this too...
declare #startdate datetime
declare #enddate datetime
set #startdate = '12-02-2009'
set #enddate = '12-05-2009'
;with num_cte as
(
select top(datediff(day,#startdate,#enddate)) ROW_NUMBER() OVER (ORDER BY c.column_id) AS rn
from sys.columns c
)
, generate_date_cte as
(
select 1 as Id,#startdate as newdate
union all
select rn+1 as Id, newdate
from num_cte
cross apply( select DATEADD(day,rn,#startdate) AS newdate) x
)
select * from generate_date_cte

Another solution
declare #startdate datetime
declare #enddate datetime
set #startdate = '12-02-2009'
set #enddate = '12-05-2009'
; with generateCalender_cte as
(
select
1 as Id
,#startdate as newdate
union all
select
c.Id + 1
,DATEADD(day,1,c.newdate)
from generateCalender_cte c
where c.newdate <#enddate
)
select * from generateCalender_cte

Try this
declare #startdate datetime
declare #enddate datetime
set #startdate = '12-02-2009'
set #enddate = '12-05-2009'
;with generateCalender_cte as
(
select
1 as Id
,#startdate DateValue
union all
select
c.Id + 1
,DateValue + 1
from generateCalender_cte c
where DateValue + 1 <= #enddate
)
select * from generateCalender_cte

Related

SQL - Return dates for 2 or 3 weeks intervals (before and after) based on a datetime value

Is there a way to specify a date (2020-01-20) and then return every 2 weeks forward and backwards between a start and finish period. So 01 Jan 2020 to 01 Mar 2020 for example. A list of of all the dates every 2 weeks from this input date.
Sample of table data for reference...
DECLARE #Source TABLE(bookingcode int, NextWeekCommDate DATETIME, Cycle int)
insert into #Source (bookingcode, NextWeekCommDate, cycle)
select 556789, '23 Mar 2020', 2
insert into #Source (bookingcode, NextWeekCommDate, cycle)
select 556790, '30 Mar 2020', 3
select * from #Source
declare #from datetime = '01 Mar 2020'
declare #to datetime = '01 Jun 2020'
Then I am trying to output the following results based on the declared#to and #from dates
bookingcode CycleOccurDate
556789 2020-03-09 00:00:00.000
556789 2020-03-23 00:00:00.000
556789 2020-04-06 00:00:00.000
556789 2020-04-20 00:00:00.000
556789 2020-05-04 00:00:00.000
556789 2020-05-18 00:00:00.000
556790 2020-03-30 00:00:00.000
556790 2020-04-20 00:00:00.000
556790 2020-05-11 00:00:00.000
So it works backwards as well from the NextWeekCommDate if the #from date is before this Thank you again
You can use a recursive CTE:
with dates as (
select convert(date, '2020-01-01') as dte
union all
select dateadd(week, 2, dte)
from cte
where dte < '2020-03-01'
)
select *
from dates;
If this can return more than 100 rows, then use option (maxrecursion 0).
It is not clear to me what '2020-01-20' has to do with the question.
Sure, you can add directly or substract fom a date field
SELECT GETDATE(), GETDATE()-14, GETDATE()+14
or in date
SELECT CAST(GETDATE() AS DATE), CAST(GETDATE()-14 AS DATE), CAST(GETDATE()+14 AS DATE)
Take a look at DATE FUNCTIONS in SQLSERVER, there are plenty of them that you may use
https://learn.microsoft.com/es-es/sql/t-sql/functions/date-and-time-data-types-and-functions-transact-sql?view=sql-server-ver15

Get every 2 weeks on particular days SQL Server

I have a query getting the days in particular day that I selected and show the days in a month. My problem is that I need every two weeks of the month. And I also need to get long date format: dddd, dd MMMM yyyy and eliminate the time. Please help me.
DECLARE #startDate DATETIME = '9/1/2019'
DECLARE #endDate DATETIME = '12/31/2019'
DECLARE #dayOfWeek INT = 1;
WITH cte_Recursion AS
(
SELECT #startDate AS [Date]
UNION ALL
SELECT DATEADD(DAY, 1, [Date])
FROM cte_Recursion
WHERE [Date] < #endDate
)
SELECT [Date]
FROM cte_Recursion
WHERE DATEPART(WEEKDAY, [Date]) = #dayOfWeek
OPTION (MAXRECURSION 0)
The data returned looks like this:
2019-09-01 00:00:00.000
2019-09-08 00:00:00.000
2019-09-15 00:00:00.000
2019-09-22 00:00:00.000
2019-09-29 00:00:00.000
2019-10-06 00:00:00.000
2019-10-13 00:00:00.000
2019-10-20 00:00:00.000
2019-10-27 00:00:00.000
2019-11-03 00:00:00.000
2019-11-10 00:00:00.000
2019-11-17 00:00:00.000
2019-11-24 00:00:00.000
And I need to get like this (every other week):
2019-09-01 00:00:00.000
2019-09-15 00:00:00.000
2019-09-29 00:00:00.000
2019-10-13 00:00:00.000
2019-10-27 00:00:00.000
2019-11-10 00:00:00.000
2019-11-24 00:00:00.000
By changing your CTE to start on the correct day of the week, you can then change the recursion to add 14 days instead of 1, giving you the desired result without further manipulation:
DECLARE #startDate DATETIME = '9/1/2019'
DECLARE #endDate DATETIME = '12/31/2019'
DECLARE #dayOfWeek INT = 1;
WITH cte_Recursion AS
(SELECT DATEADD(DAY, ((#dayOfWeek - DATEPART(WEEKDAY, #startDate)) % 7 + 7) %7, #startDate) AS [Date]
UNION ALL SELECT DATEADD(DAY, 14, [Date])
FROM cte_Recursion
WHERE DATEADD(DAY, 14, [Date]) < #endDate)
SELECT [Date] FROM cte_Recursion
Output:
Date
01/09/2019 00:00:00
15/09/2019 00:00:00
29/09/2019 00:00:00
13/10/2019 00:00:00
27/10/2019 00:00:00
10/11/2019 00:00:00
24/11/2019 00:00:00
08/12/2019 00:00:00
22/12/2019 00:00:00
Demo on dbfiddle
To change the date format to dddd, dd MMMM yyyy, simply replace the final SELECT with:
SELECT FORMAT([Date], 'dddd, dd MMMM yyyy') AS [Date] FROM cte_Recursion
Output:
Date
Sunday, 01 September 2019
Sunday, 15 September 2019
Sunday, 29 September 2019
Sunday, 13 October 2019
Sunday, 27 October 2019
Sunday, 10 November 2019
Sunday, 24 November 2019
Sunday, 08 December 2019
Sunday, 22 December 2019
Demo on dbfiddle
you can use it :
DECLARE #startDate DATETIME = '9/1/2019'
DECLARE #endDate DATETIME = '12/31/2019'
DECLARE #dayOfWeek INT = 1;
WITH cte_Recursion AS
(
SELECT #startDate AS [Date]
UNION ALL SELECT DATEADD(DAY, 1, [Date])
FROM cte_Recursion WHERE [Date] < #endDate
)
SELECT [Date] FROM cte_Recursion
WHERE DATEPART(WEEKDAY, [Date]) = #dayOfWeek
and DATEPART(WEEK, [Date]) % 2 = 0
OPTION (MAXRECURSION 0)
You could use a recursive CTE as
WITH CTE AS
(
SELECT '2019-09-01 00:00:00.000' ADate
UNION SELECT '2019-09-08 00:00:00.000'
UNION SELECT '2019-09-15 00:00:00.000'
UNION SELECT '2019-09-22 00:00:00.000'
UNION SELECT '2019-09-29 00:00:00.000'
UNION SELECT '2019-10-06 00:00:00.000'
UNION SELECT '2019-10-13 00:00:00.000'
UNION SELECT '2019-10-20 00:00:00.000'
UNION SELECT '2019-10-27 00:00:00.000'
UNION SELECT '2019-11-03 00:00:00.000'
UNION SELECT '2019-11-10 00:00:00.000'
UNION SELECT '2019-11-17 00:00:00.000'
UNION SELECT '2019-11-24 00:00:00.000'
),
F AS
(
SELECT CAST('2019-09-01 00:00:00.000' AS DATETIME) ADate
UNION ALL
SELECT DATEADD(Day, 14, F.ADate)
FROM F
WHERE ADate < '2019-11-24 00:00:00.000'
)
SELECT *
FROM F;

Find Overlap In Time Records

I have a table in a SQL Server 2012 database that logs events, with columns StartDate and EndDate. I need to aggregate all of the records within a certain time period, and determine the duration of time where any events were active, not counting overlapping durations. For example, if my table looks like this:
id StartDate EndDate
=======================================================
1 2017-08-28 12:00:00 PM 2017-08-28 12:01:00 PM
2 2017-08-28 1:15:00 PM 2017-08-28 1:17:00 PM
3 2017-08-28 1:16:00 PM 2017-08-28 1:20:00 PM
4 2017-08-28 1:30:00 PM 2017-08-28 1:35:00 PM
And my time period to search was from 2017-08-28 12:00:00 PM to 2017-08-28 2:00:00 PM, then my desired output should be:
Duration of Events Active = 00:11:00
I have been able to aggregate the records and get a total duration (basically just EndDate - StartDate), but I cannot figure out how to exclude overlapping time. Any help would be appreciated. Thanks!
How about a CTE and aggregation? This can be done with a sub-query too.
declare #table table (id int, StartDate datetime, EndDate datetime)
insert into #table
values
( 1,'2017-08-28 12:00:00 PM','2017-08-28 12:01:00 PM'),
(2,'2017-08-28 1:15:00 PM','2017-08-28 1:17:00 PM'),
(3,'2017-08-28 1:16:00 PM','2017-08-28 1:20:00 PM'),
(4,'2017-08-28 1:30:00 PM','2017-08-28 1:35:00 PM')
declare #StartDate datetime = '2017-08-28 12:00:00'
declare #EndDate datetime = '2017-08-28 14:00:00'
;with cte as(
select
id
,StartDate = case when StartDate < lag(EndDate) over (order by id) then lag(EndDate) over (order by id) else StartDate end
,EndDate
from
#table
where
StartDate >= #StartDate
and EndDate <= #EndDate),
cte2 as(
select
Dur = datediff(second, StartDate, EndDate)
from cte)
select
Dur = convert(varchar, dateadd(ms, sum(Dur) * 1000, 0), 114)
from
cte2

SQL - Generate bi-weekly end date on custom start date

I want to get a custom Fort Night period based on a given start date.
I have a table that looks like this:
IF OBJECT_ID('tempdb..#tbl1') IS NOT NULL DROP TABLE #tbl1
SET DATEFIRST 1
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-03'
SET #EndDateTime = '2017-01-28';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,1,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT ROW_NUMBER() OVER(ORDER BY DateData ASC) As ROWNum,DateData AS Date1
into #tbl1
FROM DateRange
OPTION (MAXRECURSION 0)
GO
SELECT top 10 * FROM #tbl1
Date1
2016-09-09 00:00:00.000
2016-09-10 00:00:00.000
2016-09-11 00:00:00.000
2016-09-12 00:00:00.000
2016-09-13 00:00:00.000
2016-09-14 00:00:00.000
2016-09-15 00:00:00.000
2016-09-16 00:00:00.000
2016-09-17 00:00:00.000
2016-09-18 00:00:00.000
2016-09-19 00:00:00.000
2016-09-20 00:00:00.000
2016-09-21 00:00:00.000
2016-09-22 00:00:00.000
I want to say the the first date of my bi-weekly period is 2016-09-09 and it ends 2016-09-22. How do I get bi-weekly end date for each of those dates.
So I want it to look like
Date1 FortNightEndDate
2016-09-09 00:00:00.000 2016-09-22 00:00:00.000
2016-09-10 00:00:00.000 2016-09-22 00:00:00.000
2016-09-11 00:00:00.000 2016-09-22 00:00:00.000
2016-09-12 00:00:00.000 2016-09-22 00:00:00.000
2016-09-13 00:00:00.000 2016-09-22 00:00:00.000
2016-09-14 00:00:00.000 2016-09-22 00:00:00.000
2016-09-15 00:00:00.000 2016-09-22 00:00:00.000
2016-09-16 00:00:00.000 2016-09-22 00:00:00.000
2016-09-17 00:00:00.000 2016-09-22 00:00:00.000
2016-09-18 00:00:00.000 2016-09-22 00:00:00.000
2016-09-19 00:00:00.000 2016-09-22 00:00:00.000
2016-09-20 00:00:00.000 2016-09-22 00:00:00.000
2016-09-21 00:00:00.000 2016-09-22 00:00:00.000
2016-09-22 00:00:00.000 2016-09-22 00:00:00.000
I'm using SQL Server 2005.
ANSWER:
I was able to solve it using the following code. Essentially I just created 3 tables:
StartDates
EndDates
InbetweenDates
The Start/EndDates tables had just the start and End of my 2 week period and an ID (Row Number)
The InbetweenDates table had all the dates between the 2 dates and also had a ID column but instead of going up 1 every row, it went up 1 every 14 rows.
Then I just joined the 3 tables. Essentially, the Start/EndDates tables were lookup tables.
I got the RowNumber on every 14 days code from here.
-- BEtween Dates
IF OBJECT_ID('tempdb..#BetweenDates') IS NOT NULL DROP TABLE #BetweenDates
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-09'
SET #EndDateTime = '2017-04-30';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,1,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT
DateData
into #BetweenDates
FROM DateRange
OPTION (MAXRECURSION 0)
GO
select
(case when convert(int, (ROW_NUMBER() OVER (Order by (select 0)) % 14))=0 then 0 else 1 end)
+ convert(int, (ROW_NUMBER() OVER (Order by (select 0)) / 14)) as ID
,DateData
INTO #BetweenDates_ID
from #BetweenDates
-- Start Dates
IF OBJECT_ID('tempdb..#StartDates') IS NOT NULL DROP TABLE #StartDates
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-09'
SET #EndDateTime = '2017-04-30';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,14,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT ROW_NUMBER() OVER(ORDER BY DateData ASC) As ID,DateData
into #StartDates
FROM DateRange
OPTION (MAXRECURSION 0)
GO
-- End Dates
IF OBJECT_ID('tempdb..#EndDates') IS NOT NULL DROP TABLE #EndDates
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-22'
SET #EndDateTime = '2017-04-30';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,14,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT ROW_NUMBER() OVER(ORDER BY DateData ASC) As ID,DateData
into #EndDates
FROM DateRange
OPTION (MAXRECURSION 0)
GO
--SELECT * FROM #StartDates
--SELECT * FROM #EndDates
--SELECT * FROM #BetweenDates_ID
SELECT
st.DateData AS StartDate
,ed.DateData AS EndDate
,bd.DateData AS BetweenDate
FROM
#StartDates st
JOIN
#EndDates ed
ON st.ID = ed.ID
LEFT JOIN
#BetweenDates_ID bd
ON st.ID = bd.ID
Try this:
SELECT Date1,
DATEADD(DD, -1, DATEADD(WW,2,Date1)) AS FortNightEndDate
FROM #tbl1

single query to retrieve data in sql for different shift patterns

I have two working shifts: 8:00:00 to 16:30:00 and 20:00:00 to 06:00:00. I want to create a stored procedure that will retrieve data from an SQL table when I pass the date
This is my tables Table1
ID DateTime EmpID
-------------------------------------
47 2014-12-07 08:00:00 1111
47 2014-12-07 15:25:00 1235
47 2014-12-07 23:55:00 4569
47 2014-12-08 00:00:00 4563
47 2014-12-08 02:00:00 7412
59 2014-12-08 04:00:00 8523
59 2014-12-05 10:30:00 5632
Table Product
ID DateTime ProductMade
47 2014-12-07 11:00:00 Milk
47 2014-12-07 08:00:00 Juice
47 2014-12-08 00:00:00 Bread
47 2014-12-08 04:00:00 Cakes
47 2014-12-07 21:00:00 Juice
89 2014-12-01 04:00:00 bread
query for shift 2 18:00 to 06:00
select Count(EmpID) as ID,Count (ProductMade) ProductsTotal, Count(EmpID) * Count (ProductMade) as Total
from Table 1 as T1
inner join Table_Product as Prod on t1.ID = Prod.ID
where T1.DateTime BETWEEN DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()-2), 0) + '18:00' and DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()-1), 0) + '06:00' and DepartmentID=47
So this will get all the records that has the same ID matching
Then I have to do another query for the first shift.
between 08:00 to 16:30
select Count(EmpID) as ID,Count (ProductMade) ProductsTotal, Count(EmpID) * Count (ProductMade) as Total
from Table 1 as T1
inner join Table_Product as Prod on t1.ID = Prod.ID
where DATEDIFF(day, CONVERT(VARCHAR(10), GETDATE(),110), CONVERT(VARCHAR(10), T1.DateTime,110))=-2 and DATEPART(HOUR,T1.DateTime) BETWEEN '07' AND '16' and DepartmentID=47
OutPUT FirstShift 08 :00 to 16:30
ID ProductMade Total
2 2 4
OutPut Second Shift 20:00 to 06:00
ID ProductMade Total
3 3 9
so the second shift request a the startdate of -2 and the end date of -1 this is the part thats different from the day shift. cause i will pass the number of days previous i want to go backwards from a select box
This will product something in 1 go. I'm still not sure what output you are looking for. What does the DateTime in the Table_Product represent?
DECLARE #days int
SET #days = 4;
WITH Tab as (
Select case when DATEPART(hour, t.DateTime) between 8 and 16 then 'A' else 'B' end AS Shift, *
from Table1 t
where t.DateTime between DateAdd(hour, 8, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days)))
and DateAdd(hour, 30, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days)))
),
Prod as (
Select case when DATEPART(hour, t.DateTime) between 8 and 16 then 'A' else 'B' end AS Shift, *
from Table_Product t
where t.DateTime between DateAdd(hour, 8, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days)))
and DateAdd(hour, 30, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days))))
Select ID, ProductMake, Shift, Count(*), (Select Count(*) from Tab where ID = t1.ID and Shift = t1.Shift) Total from Prod t1
GROUP BY ID, Shift, ProductMake
Something like this?
where ((#shift = 1 and t1.datetime between ... ) or (#shift = 2 and datediff ... ))