missing time range in a day - sql

I have a table like this:
create table time_sheet
(
StatusCode char(1),
start_time datetime,
end_time datetime
)
insert into time_sheet values
('W','2012-08-01 10:00:00','2012-08-01 12:00:00'),
('D','2012-08-01 12:00:00','2012-08-01 14:00:00'),
('N','2012-08-01 16:00:00','2012-08-01 18:00:00')
The output should be like this:
StatusCode start_time end_time
B 2012-08-01 08:00:00.000 2012-08-01 10:00:00.000
W 2012-08-01 10:00:00.000 2012-08-01 12:00:00.000
D 2012-08-01 12:00:00.000 2012-08-01 14:00:00.000
B 2012-08-01 14:00:00.000 2012-08-01 16:00:00.000
N 2012-08-01 16:00:00.000 2012-08-01 18:00:00.000
B 2012-08-01 18:00:00.000 2012-08-01 20:00:00.000
The beging and end of the day are declared as below.
declare #begingOfDay datetime='2012-08-01 08:00:00.000'
declare #endOfDay datetime='2012-08-01 20:00:00.000'
Basically I want to have missing time range records in the result set between begingOfDay and endOfDay with statusCode B . Please see that in the output there are 3 records added with StatusCode B
Could anybody help with this?

Your sample data (note, Ts added to strings to enforce unambiguous date conversions):
create table time_sheet
(
StatusCode char(1),
start_time datetime,
end_time datetime
)
insert into time_sheet values
('W','2012-08-01T10:00:00','2012-08-01T12:00:00'),
('D','2012-08-01T12:00:00','2012-08-01T14:00:00'),
('N','2012-08-01T16:00:00','2012-08-01T18:00:00')
declare #begingOfDay datetime='2012-08-01T08:00:00.000'
declare #endOfDay datetime='2012-08-01T20:00:00.000'
And the query:
;with AllDTs as (
select #begingOfDay as TimePoint
union
select #endOfDay
union
select start_time from time_sheet
union
select end_time from time_sheet
), OrderedDTs as (
select TimePoint,ROW_NUMBER() OVER (ORDER BY TimePoint) as rn
from AllDTs
), Periods as (
select o1.TimePoint as start_time,o2.TimePoint as end_time
from
OrderedDTs o1
inner join
OrderedDTs o2
on
o1.rn = o2.rn-1
)
select
COALESCE(ts.StatusCode,'B') as StatusCode,
p.start_time,
p.end_time
from
Periods p
left join
time_sheet ts
on
p.start_time = ts.start_time and
p.end_time = ts.end_time
Result:
StatusCode start_time end_time
---------- ----------------------- -----------------------
B 2012-08-01 08:00:00.000 2012-08-01 10:00:00.000
W 2012-08-01 10:00:00.000 2012-08-01 12:00:00.000
D 2012-08-01 12:00:00.000 2012-08-01 14:00:00.000
B 2012-08-01 14:00:00.000 2012-08-01 16:00:00.000
N 2012-08-01 16:00:00.000 2012-08-01 18:00:00.000
B 2012-08-01 18:00:00.000 2012-08-01 20:00:00.000
Note, I've proceeded on the assumption that there are no overlapping time periods in the original table. The first CTE (AllDTs) just finds all unique datetime values that are of interest to us. OrderedDTs and Periods than arrange all of these datetime values into successive periods. The final query then takes each of these periods, and attempts to match them back to the original table, if possible. If not, then it's obviously a B period.

Try This one:
declare #begingOfDay datetime='2012-08-01 08:00:00.000'
declare #endOfDay datetime='2012-08-01 20:00:00.000'
declare #begingOfDay datetime='2012-08-01 08:00:00.000'
declare #endOfDay datetime='2012-08-01 20:00:00.000'
;WITH CTEMain as (select ROW_NUMBER() over (order by (select 0)) as id,StatusCode,start_time,end_time from time_sheet)
,CTE2 as (
select * from (
select CASE WHEN start_time > #begingOfDay then 'B' else StatusCode end as statusCode,
CASE WHEN start_time > #begingOfDay then #begingOfDay else start_time end as start_time,
CASE WHEN start_time > #begingOfDay then start_time else end_time end as end_time
FROM CTEMain where id=1
UNION
select StatusCode,start_time,end_time from CTEMain
union
select 'B'
,CASE WHEN CAST(((select c.start_time from CTEMain c where c.id=t1.id+1)-t1.end_time) as time) > '00:00:00' then end_time else null end as start_time
,CASE WHEN CAST(((select c.start_time from CTEMain c where c.id=t1.id+1)-t1.end_time) as time) > '00:00:00' then end_time+((select c.start_time from CTEMain c where c.id=t1.id+1)-t1.end_time) else null end as start_time
from CTEMain t1
) a)
select * from (
select * from CTE2 where start_time is not null
union all
select 'B',CASE WHEN MAX(end_time) = #endOfDay then null else MAX(end_time) end as start_time,#endOfDay as end_time from CTE2) a order by start_time

Related

Time until midnight between two date and time columns

I need help with my query to calculate the time until midnight between two date and time columns
break down by day
This is the main table:
ID
Start_Time
End_time
DateDiff
32221
01-01-2022 13:10:00
01-03-2022 13:10:00
2880
My query:
SELECT
start_time.ID,
start_time.Date_Time AS Start_time,
end_time.Date_Time AS End_time,
DATEDIFF(minute, start_time.Date_Time, end_time.Date_Time) AS DateDiff
FROM
Main
what I need is similar to this:
ID
Date_start
End_time
DateDiff
32221
01-01-2022 13:10:00
01-01-2022 23:59:59
654
32221
01-02-2022 00:00:00
01-02-2022 23:59:59
1440
32221
01-03-2022 00:00:00
01-03-2022 13:10:00
781
how i can do that?
You can loop through the times, always adding the time untill midnight, untill your 'start_time + 1 day' is bigger than your end_time.
The below code can be run directly in SQL (mind the date notation, my SQL is in united states notation, so if yours is in Europe this will give you back results for 3 months instead of 3 days);
DECLARE #start_time datetime2 = '01/01/2022 13:00:00';
DECLARE #end_time datetime2 = '03/01/2022 14:00:00';
DECLARE #daily_end_time datetime2=NULL;
DECLARE #Table Table (start_time datetime2, end_time datetime2, diff nvarchar(8));
DECLARE #diff_minutes_start int = DATEDIFF(MINUTE,#start_time,DateDiff(day,0,dateadd(day,1,#start_time)));
DECLARE #diff_minutes_end int = DATEDIFF(minute,#end_time,DateDiff(day,0,dateadd(day,1,#end_time)))
SET #daily_end_time = DATEADD(mi,#diff_minutes_start,#start_time)
WHILE #daily_end_time < #end_time
BEGIN
INSERT INTO #Table (start_time,end_time,diff)
VALUES (
#start_time,
CASE WHEN DATEADD(day,1,#daily_end_time) > #end_time THEN #end_time ELSE
#daily_end_time END,
CASE WHEN DATEADD(day,1,#daily_end_time) > #end_time THEN #diff_minutes_end ELSE
#diff_minutes_start END )
SET #daily_end_time = DATEADD(mi,#diff_minutes_start,#start_time)
SET #start_time = DATEADD(mi,1,#daily_end_time);
select #diff_minutes_start =
DATEDIFF(MINUTE,#start_time,DateDiff(day,0,dateadd(day,1,#start_time)));
select #diff_minutes_end = DATEDIFF(minute,#end_time,DateDiff(day,0,dateadd(day,1,#end_time)))
END
SELECT * FROM #Table
And the results:
You may use a recursive CTE as the following:
With CTE As
(
Select ID, Start_Time, End_time, DATEADD(Second, -1, DATEADD(Day, DATEDIFF(Day,0, Start_Time), 1)) et
From main
Union All
Select C.ID, DATEADD(Second, 1, C.et), C.End_time, DATEADD(Day, 1, C.et)
From CTE C Join main T
On C.ID = T.ID
Where DATEADD(Second, 1, C.et) <= C.End_time
)
Select ID, Start_Time,
Case When End_Time <= et Then End_Time Else et End As End_Time,
DATEDIFF(Minute, Start_Time, DATEADD(Second, 1, Case When End_Time <= et Then End_Time Else et End)) As [DateDiff]
From CTE
Order By ID, Start_Time
See a demo with extended data sample from db<>fiddle.
You can also solve this with a tally table, using the expanded (to show different cases) sample data
ID
StartTime
EndTime
32221
2022-01-01 13:10:00
2022-01-03 13:10:00
32222
2022-02-02 10:10:00
2022-02-02 17:10:00
32223
2022-03-03 19:10:00
2022-03-04 08:10:00
32224
2022-04-04 19:10:00
2022-04-08 08:10:00
and the code
with cteSampleData as ( --Enter some sample data, include spans of 0, 1, and >1 days
SELECT * --Note that we need CONVERT to make sure the dates are treated as datetime not string!
FROM (VALUES(32221, CONVERT(datetime2(0), '01-01-2022 13:10:00'), CONVERT(datetime2(0), '01-03-2022 13:10:00') )
, (32222, '02-02-2022 10:10:00', '02-02-2022 17:10:00')
, (32223, '03-03-2022 19:10:00', '03-04-2022 08:10:00')
, (32224, '04-04-2022 19:10:00', '04-08-2022 08:10:00')
) as Samp(ID, StartTime, EndTime)
), cteWithControl as ( --Add some fields to make testing cledarer - you could do this as part of a subsequent step instead
SELECT *
, CONVERT(date, StartTime) as StartDate , CONVERT(date, EndTime) as EndDate
, DATEDIFF(day, StartTime , EndTime) as DiffDays
--, DATEDIFF(day, CONVERT(date, StartTime) , CONVERT(date, EndTime)) as DiffDays
FROM cteSampleData
), cteTally as ( --Get a list of integers to represent days, assume nothing lasts longer than a year
SELECT top 365 ROW_NUMBER() over (ORDER BY name) as Tally
FROM sys.objects --just a table we know has over 300 rows, look up tally tables for other generation methods
)--The real work begins below, partition the data into "same day" and "multi-day" spans
, cteSet as (
SELECT ID, StartTime, EndTime, DiffDays, 1 as DayNumber
FROM cteWithControl WHERE DiffDays = 0
UNION ALL
SELECT ID --For multi-day, cross with the tally table and treat first and last days special
, CASE WHEN T.Tally = 1 THEN StartTime --For the first day the start time is the real time
ELSE DATEADD (day, T.Tally - 1, startdate) END as StartTime --Otherwise it's the start of the day
, CASE WHEN T.Tally = DiffDays + 1 THEN EndTime --For the last day the end is the real end
ELSE DATEADD (second, -1, CONVERT(DATETIME2(0), DATEADD (day, T.Tally, startdate)))
END as EndTime --otherwise 1 second less than the next day
, DiffDays, Tally as DayNumber
FROM cteWithControl as D CROSS JOIN cteTally as T
WHERE DiffDays > 0 AND T.Tally <= D.DiffDays + 1
)--Now we display the results and calculate the length (in minutes) of each span
SELECT *
, DATEDIFF(MINUTE, StartTime, EndTime) as DateDiff
FROM cteSet
ORDER BY ID, DayNumber
we get the output
ID
StartTime
EndTime
DiffDays
DayNumber
DateDiff
32221
2022-01-01 13:10:00
2022-01-01 23:59:59
2
1
649
32221
2022-01-02 00:00:00
2022-01-02 23:59:59
2
2
1439
32221
2022-01-03 00:00:00
2022-01-03 13:10:00
2
3
790
32222
2022-02-02 10:10:00
2022-02-02 17:10:00
0
1
420
32223
2022-03-03 19:10:00
2022-03-03 23:59:59
1
1
289
32223
2022-03-04 00:00:00
2022-03-04 08:10:00
1
2
490
32224
2022-04-04 19:10:00
2022-04-04 23:59:59
4
1
289
32224
2022-04-05 00:00:00
2022-04-05 23:59:59
4
2
1439
32224
2022-04-06 00:00:00
2022-04-06 23:59:59
4
3
1439
32224
2022-04-07 00:00:00
2022-04-07 23:59:59
4
4
1439
32224
2022-04-08 00:00:00
2022-04-08 08:10:00
4
5
490

How to Create Times Based on an Interval and Start Time?

I am performing some scheduling optimization in my database.
For the job schedule, many records appear like this
Time NextRunTime
Every 3 hours 2019-06-03 10:00:00
Every 3 hours 2019-05-28 20:00:00
Every 4 hours 2017-07-31 18:00:00
Every 1 hours 2019-06-03 14:00:00
Every 4 hours 2017-06-08 16:00:00
What is an efficient means to split the "every" records into separate records within the 24 hour day?
For example, for the first record (every 3 hours from 10:00), I need it to insert the following into a table.
Time
13:00:00
16:00:00
19:00:00
22:00:00
01:00:00
04:00:00
07:00:00
10:00:00
I need to repeat this for every record in the first table with "every".
Can anybody help?
If you want to do this correctly you will need a tally table. First let's look at the logic required to solve this.
DECLARE #starttime DATETIME = '2019-06-03 10:00:00', #hours INT = 3;
SELECT t.N, Tm = CAST(DATEADD(HOUR,t.N*3,#startTime) AS TIME)
FROM
(
SELECT TOP (24/#hours) ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS a(x),
(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS b(x)
) AS t(N);
Returns:
N Tm
------- ----------------
1 13:00:00.0000000
2 16:00:00.0000000
3 19:00:00.0000000
4 22:00:00.0000000
5 01:00:00.0000000
6 04:00:00.0000000
7 07:00:00.0000000
8 10:00:00.0000000
Now for some sample data and a record identifier (named "someId") so we can calculate this for all rows in your table.
-- Sample Data
DECLARE #yourTable TABLE (someId INT IDENTITY PRIMARY KEY, freq INT, NextRunTime DATETIME);
INSERT #yourTable(freq, NextRunTime) VALUES (3, '2019-06-03 10:00:00'),
(3, '2019-05-28 20:00:00'),(4, '2017-07-31 18:00:00'),
(1, '2019-06-03 14:00:00'),(4, '2017-06-08 16:00:00');
-- Solution
SELECT yt.someId, f.Tm
FROM #yourTable AS yt
CROSS APPLY
(
SELECT t.N, CAST(DATEADD(HOUR,t.N*yt.freq,yt.NextRunTime) AS TIME)
FROM
(
SELECT TOP (24/yt.freq) ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS a(x),
(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS b(x)
) AS t(N)
) AS f(N,Tm);
Returns:
someId Tm
----------- ----------------
1 13:00:00.0000000
1 16:00:00.0000000
1 19:00:00.0000000
1 22:00:00.0000000
1 01:00:00.0000000
1 04:00:00.0000000
1 07:00:00.0000000
1 10:00:00.0000000
2 23:00:00.0000000
2 02:00:00.0000000
2 05:00:00.0000000
2 08:00:00.0000000
2 11:00:00.0000000
2 14:00:00.0000000
2 17:00:00.0000000
2 20:00:00.0000000
3 22:00:00.0000000
3 02:00:00.0000000
3 06:00:00.0000000
3 10:00:00.0000000
3 14:00:00.0000000
3 18:00:00.0000000
4 15:00:00.0000000
4 16:00:00.0000000
4 17:00:00.0000000
4 18:00:00.0000000
4 19:00:00.0000000
4 20:00:00.0000000
4 21:00:00.0000000
4 22:00:00.0000000
4 23:00:00.0000000
4 00:00:00.0000000
4 01:00:00.0000000
4 02:00:00.0000000
4 03:00:00.0000000
4 04:00:00.0000000
4 05:00:00.0000000
4 06:00:00.0000000
4 07:00:00.0000000
4 08:00:00.0000000
4 09:00:00.0000000
4 10:00:00.0000000
4 11:00:00.0000000
4 12:00:00.0000000
4 13:00:00.0000000
4 14:00:00.0000000
5 20:00:00.0000000
5 00:00:00.0000000
5 04:00:00.0000000
5 08:00:00.0000000
5 12:00:00.0000000
5 16:00:00.0000000
I have always thought that a recursive cte is a nice way to solve your query:
-- the sample data
declare #data as table (freq varchar(100), tmst datetime, each_ int)
insert into #data
select s.freq,s.tmst,
convert(int,replace(replace(freq,'Every ',''),' hours','')) as each_
from (
select 'Every 4 hours' as freq, convert(datetime,'2019-06-02 10:00:00') as tmst union all
select 'Every 3 hours' as freq, convert(datetime,'2019-06-02 11:00:00') as tmst union all
select 'Every 2 hours' as freq, convert(datetime,'2019-06-02 10:00:00') as tmst
) s
-- the query
;with cte as (
select freq, tmst, each_, null t1 from #data
union all
select freq, tmst, each_, isnull(t1,datepart(hour,tmst)) + each_
from cte
where isnull(t1,datepart(hour,tmst)) + each_ <= 23
)
select freq,
isnull(convert(datetime, convert(varchar(8),tmst,112) + ' ' + (convert(varchar(100),t1) + ':00:00' ), 120),tmst)
from cte
order by 1, 2
With this second version, you can get all the ranges from 0 to 23 (in the previous example you got just from the starting point to the 23)
-- the query
;with findfirst as (
select freq, tmst, datepart(hour,tmst) as fhour, datepart(hour,tmst) as init, each_ from #data
union all
select freq, tmst, fhour, init - each_, each_ from findfirst where init - each_ >= 0
),
cte as (
select min(init) as init, freq, tmst, each_, fhour from findfirst group by freq, tmst, each_, fhour
union all
select init + each_, freq, tmst, each_, fhour from cte where init + each_ <= 23
)
select freq,tmst,convert(time, right('0' + convert(varchar(2),init), 2) + ':00:00')
from cte order by freq,init,each_
Remember to continue using the #data table.
Output:
First drop any temp tables that have the names of the temp tables you will create:
IF OBJECT_ID(N'tempdb..#Interval', N'U') IS NOT NULL DROP TABLE #Interval
GO
IF OBJECT_ID(N'tempdb..#Interval2', N'U') IS NOT NULL DROP TABLE #Interval2
GO
IF OBJECT_ID(N'tempdb..#Runstart', N'U') IS NOT NULL DROP TABLE #Runstart
GO
Then create, and insert data into, your temp tables:
CREATE TABLE #Interval
(
_Time NVARCHAR(13),
NextRunTime DATETIME
)
GO
INSERT INTO #Interval VALUES ('Every 3 hours','2019-06-03 10:00:00')
INSERT INTO #Interval VALUES ('Every 3 hours','2019-05-28 20:00:00')
INSERT INTO #Interval VALUES ('Every 4 hours','2017-07-31 18:00:00')
INSERT INTO #Interval VALUES ('Every 1 hours','2019-06-03 14:00:00')
INSERT INTO #Interval VALUES ('Every 4 hours','2017-06-08 16:00:00')
GO
CREATE TABLE #Interval2
(
RunID INT IDENTITY(10001,1) NOT NULL PRIMARY KEY,
_Time INT NOT NULL,
NextRunTime DATETIME NOT NULL
)
GO
The code below ensures that you get the right interval for each run start, note: If the number of hours are ever 10 or more, it would be necessary to add some more code here to make the number of digits selected conditional upon the length of the string which contains them, let me know if you need this code too.
INSERT INTO #Interval2 (_TIME,NextRunTime) SELECT SUBSTRING(_Time,7,1),NextRunTime FROM #Interval WHERE LEFT(_Time,5) = 'Every'
GO
CREATE TABLE #Runstart
(
StartID INT IDENTITY(10001,1) NOT NULL PRIMARY KEY,
RunID INT NOT NULL,
[Start_DTTM] DATETIME
)
GO
Next populate the #RUNSTART table using this loop:
DECLARE #RunID INT = 10001
DECLARE #RunTime INT = (SELECT _TIME FROM #Interval2 WHERE RunID = #RunID)
DECLARE #NextRun DATETIME = (SELECT NextRunTime FROM #Interval2 WHERE RunID = #RunID)
WHILE #RunID <= (SELECT MAX(RunID) FROM #Interval2)
BEGIN
WHILE #NextRun < (SELECT DATEADD(DD,1,NextRunTime) FROM #Interval2 WHERE RunID = #RunID)
BEGIN
INSERT INTO #Runstart (RunID,[Start_DTTM]) SELECT #RunID,DATEADD(HH,#RunTime,#NextRun)
SET #NextRun = (SELECT DATEADD(HH,#RunTime,#NextRun))
END
SET #RunID = #RunID+1
SET #RunTime = (SELECT _TIME FROM #Interval2 WHERE RunID = #RunID)
SET #NextRun = (SELECT NextRunTime FROM #Interval2 WHERE RunID = #RunID)
END
GO
SELECT StartID, RunID,CONVERT(VARCHAR,START_DTTM,108) AS Start_time FROM #RUNSTART

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

SQL query stuck - comparison on different lines

I m working on a very weird problem with SQL where I have to compare previous rows
Number start_date end_date
----- ------- ------------
1 2011-06-07 00:00:00.000 2011-07-10 00:00:00.000
2 2011-10-11 00:00:00.000 2011-10-11 00:00:00.000
3 2011-10-26 00:00:00.000 2011-10-29 00:00:00.000
4 2011-10-29 00:00:00.000 2011-11-15 00:00:00.000
Here , I have to compare the start_date and end_date on the two different line and create a view out of it.
(If the start_date is less than the previous end_date , then criteria is set to 1).
Well it should compare 2011-10-26 00:00:00.000 for 3 and 2011-10-27 00:00:00.000 on 2 for 30 days
Number start_date end_date Criteria
----- ----------- ---------------- ------------
1 2011-06-07 00:00:00.000 2011-07-10 00:00:00.000 0
2 2011-10-11 00:00:00.000 2011-10-11 00:00:00.000 0
3 2011-10-26 00:00:00.000 2011-10-29 00:00:00.000 1
4 2011-10-30 00:00:00.000 2011-11-15 00:00:00.000 1
I m confused how should I proceed with this.
Any help would be helpful !!!!
Thanks !!!
The most straightforward way to do this is to use a subquery:
select A.number, a.start_date, a.end_date,
CASE WHEN start_date < dateadd(d,30,(select TOP(1) b.end_date
from mytable B
where B.number < A.number
order by B.number desc)) then 1 else 0 end Criteria
from mytable A
Note: If the start date is the 29th day following the previous row's end date, Criteria becomes 1. By the 30th day onwards, it is 0. Tweak the 30 in the query as required.
Sample:
create table mytable (
Number int primary key,
start_date datetime,
end_date datetime);
insert mytable
select 1, '2011-06-07', '2011-07-10' union all
select 2, '2011-10-11', '2011-10-27' union all
select 3, '2011-10-26', '2011-10-29' union all
select 4, '2011-10-29', '2011-11-15'
Result:
number start_date end_date Criteria
1 2011-06-07 00:00:00.000 2011-07-10 00:00:00.000 0
2 2011-10-11 00:00:00.000 2011-10-27 00:00:00.000 0
3 2011-10-26 00:00:00.000 2011-10-29 00:00:00.000 1
4 2011-10-29 00:00:00.000 2011-11-15 00:00:00.000 0
Try using case like this:
create view vDates as
select Number,start_date,end_date,
case
when start_date<end_date
then 0
else 1
end as Criteria
from tab
SQL Fiddle Demo
A more readable way is create a function and send the correct dates:
Function:
create function [dbo].[CompareDates] (
#START_DATE datetime,
#PREVIOUS_END_DATE datetime
)
RETURNS int
AS
BEGIN
if #START_DATE < #PREVIOUS_END_DATE
return 1
return 0
END
Query (using subquery):
declare #dates table
(
number int,
start datetime,
end_date datetime
)
insert into #dates values
(1, '2011-06-07 00:00:00.000', '2011-07-10 00:00:00.000'),
(2, '2011-10-11 00:00:00.000', '2011-10-27 00:00:00.000'),
(3, '2011-10-26 00:00:00.000', '2011-10-29 00:00:00.000'),
(4, '2011-10-29 00:00:00.000', '2011-11-15 00:00:00.000')
select *, dbo.CompareDates(dates.end_date, dates.previous_end_date) from
(
select number, start, end_date,
(select TOP 1 end_date
from #dates d2
where d2.number < d1.number
order by d2.number desc) as previous_end_date
from #dates d1
) dates

how to display weekdays from below two days (Monday and Friday)?

how to display weekdays from below two days (Monday and Friday) Using SQL QUERY?
Date_From= 01/03/2011
Date_To =15/03/2011
I need output like below
Date_From Date_To
01/03/2011 01/03/2011
04/03/2011 04/03/2011 'Friday
05/03/2011 06/03/2011
07/03/2011 07/03/2011 'Monday
08/03/2011 10/03/2011
11/03/2011 11/03/2011 'Friday
12/03/2011 13/03/2011
14/03/2011 14/03/2011 'Monday
15/03/2011 15/03/2011
hoping your help
select
t1.Date_From,
t1.Date_To,
case when DATENAME(dw,t1.Date_to) IN ('friday','monday') THEN DATENAME(dw,t1.Date_to) else NULL END
from table t1
This is using Oracle. I can get the 15th to show up if I use Oracle analytic functions, but I don't know of a portable way to get the result in one row to depend on the existence of other rows. Also, due to the Cartesian product, do not use this without limiting it to a small number of rows.
select to_char(d1.d, 'DD/MM/YYYY')
, to_char(d2.d, 'DD/MM/YYYY')
, decode(d1.n, 'MONDAY', '''Monday', 'FRIDAY', '''Friday')
from (select to_date('2011-02-28') + rownum as d
, to_char(to_date('2011-02-28') + rownum, 'FMDAY') as n
from user_objects where rownum <= 15) d1
, (select to_date('2011-02-28') + rownum as d
, to_char(to_date('2011-02-28') + rownum, 'FMDAY') as n
from user_objects where rownum <= 15) d2
where d1.d <= d2.d
and d2.d - d1.d < 7
and ((d1.d = d2.d and d1.n in ('MONDAY', 'FRIDAY'))
or (d1.n = 'TUESDAY' and d2.n = 'THURSDAY')
or (d1.n = 'SATURDAY' and d2.n = 'SUNDAY'))
order by d1.d, d2.d;
This is for SQL Server 2005+.
DECLARE #Date_From datetime, #Date_To datetime;
SET #Date_From = '20110301';
SET #Date_To = '20110315';
WITH datelist AS (
SELECT
Date = #Date_From,
GroupID = 1
UNION ALL
SELECT
Date = DATEADD(day, 1, Date),
GroupID = CASE
WHEN DATENAME(dw, Date) IN ('Sunday', 'Monday', 'Thursday', 'Friday')
THEN 1
ELSE 0
END + GroupID
FROM datelist
WHERE Date < #Date_To
)
SELECT
Date_From = MIN(Date),
Date_To = MAX(Date)
FROM datelist
GROUP BY GroupID
Output:
Date_From Date_To
----------------------- -----------------------
2011-03-01 00:00:00.000 2011-03-03 00:00:00.000
2011-03-04 00:00:00.000 2011-03-04 00:00:00.000
2011-03-05 00:00:00.000 2011-03-06 00:00:00.000
2011-03-07 00:00:00.000 2011-03-07 00:00:00.000
2011-03-08 00:00:00.000 2011-03-10 00:00:00.000
2011-03-11 00:00:00.000 2011-03-11 00:00:00.000
2011-03-12 00:00:00.000 2011-03-13 00:00:00.000
2011-03-14 00:00:00.000 2011-03-14 00:00:00.000
2011-03-15 00:00:00.000 2011-03-15 00:00:00.000