data grouping according to relevant values in sql server - sql

the data is in 15 minute interval:
Time Value
2010-01-01 00:15 3
2010-01-01 00:30 2
2010-01-01 00:45 4
2010-01-01 01:00 5
2010-01-01 01:15 1
2010-01-01 01:30 3
2010-01-01 01:45 4
2010-01-01 02:00 12
2010-01-01 02:15 13
2010-01-01 02:30 12
2010-01-01 02:45 14
2010-01-01 03:00 15
2010-01-01 03:15 3
2010-01-01 03:30 2
2010-01-01 03:45 3
2010-01-01 04:00 5
..........
..........
..........
2010-01-02 00:00
Typically there will be 96 points.
According to the values, we may notice that the values from 00:15 to 01:45 are close to each other, and from 02:00 to 03:00 they are close to each other, and from 03:15 to 04:00 they are close to each other.
Based on the "close to each other" rule, I want the data to be "grouped" into 3 parts:
00:15 to 01:45
02:00 to 03:00
03:15 to 04:00
Please consider that the data could be random, and could be grouped into more than 3 parts according to the rule defined above, but maximum should not be more than 10 parts. And the grouping must honor the time sequence, for example, you cannot just put 00:15/02:30/04:45 into 1 group because these 3 points are NOT consecutive.
Please give some thoughts how to implement it in t-sql.
updated:
The value could be:
Time Value
2010-01-01 00:15 3
2010-01-01 00:30 2
2010-01-01 00:45 4
2010-01-01 01:00 5
2010-01-01 01:15 1
2010-01-01 01:30 3
2010-01-01 01:45 4
2010-01-01 02:00 12
2010-01-01 02:15 13
2010-01-01 02:30 4 --suddenly decreased
2010-01-01 02:45 14
2010-01-01 03:00 15
2010-01-01 03:15 3
2010-01-01 03:30 2
2010-01-01 03:45 3
2010-01-01 04:00 5
..........
..........
..........
2010-01-02 00:00
for these kinds of situation, we should not group 02:30 separately, because we want the group size has to be at least 3 points, and we will put that point (02:30) to the previous group (from 02:00 to 03:00).

Declare and populate testdata:
set nocount on
declare #result table(mintime datetime, maxtime datetime)
declare #t table(time datetime, value int)
-- variation is how much difference will be allowed from one row to the next
declare #variation int
set #variation = 5
insert #t values('2010-01-01 00:15',3)
insert #t values('2010-01-01 00:30',2)
insert #t values('2010-01-01 00:45',4)
insert #t values('2010-01-01 01:00',5)
insert #t values('2010-01-01 01:15',1)
insert #t values('2010-01-01 01:30',3)
insert #t values('2010-01-01 01:45',4)
insert #t values('2010-01-01 02:00',12)
insert #t values('2010-01-01 02:15',13)
insert #t values('2010-01-01 02:30',12)
insert #t values('2010-01-01 02:45',14)
insert #t values('2010-01-01 03:00',15)
insert #t values('2010-01-01 03:15',3)
insert #t values('2010-01-01 03:30',2)
insert #t values('2010-01-01 03:45',3)
insert #t values('2010-01-01 04:00',5)
Code:
a:
;with t as
( -- add a rownumber
select *, rn = row_number() over(order by time) from #t
), a as
(-- increase group if current row's value varies more than #variation from last row's value
select time, value, rn, 0 grp from t where rn = 1
union all
select t.time, t.value, t.rn, case when t.value between
a.value - #variation and a.value +#variation
then grp else grp+1 end
from t join a on
t.rn = a.rn +1
)
insert #result
select min(time), max(time) from a group by grp
if ##rowcount > 10
begin
-- this will activate if more than 10 groups of numbers are found
-- start over with higher tolerance for variation
set #variation=#variation + 1
delete #result
goto a
end
select convert(char(5), mintime,114) + ' to ' + convert(char(5), maxtime,114)
from #result
Result here:
https://data.stackexchange.com/stackoverflow/q/110891/declare-and-populate-testdata

Since your question changed so much, here is a new answer to the new question, I only included the code part.
declare #t table(time datetime, value int)
declare #variation float
set #variation = 2
set nocount on
insert #t values('2010-01-01 00:15',3)
insert #t values('2010-01-01 00:30',2)
insert #t values('2010-01-01 00:45',4)
insert #t values('2010-01-01 01:00',5)
insert #t values('2010-01-01 01:15',1)
insert #t values('2010-01-01 01:30',3)
insert #t values('2010-01-01 01:45',4)
insert #t values('2010-01-01 02:00',52)
insert #t values('2010-01-01 02:15',5)
insert #t values('2010-01-01 02:30',52)
insert #t values('2010-01-01 02:45',54)
insert #t values('2010-01-01 03:00',55)
insert #t values('2010-01-01 03:15',3)
insert #t values('2010-01-01 03:30',2)
insert #t values('2010-01-01 03:45',3)
insert #t values('2010-01-01 04:00',5)
declare #result table(mintime datetime, maxtime datetime)
a:
delete #result
;with t as
(
select *, rn = row_number() over(order by time), log(value) lv from #t where datediff(day, time, '2010-01-01') = 0
), a as
(
select time, lv, rn, 0 grp from t where rn = 1
union all
select t1.time, a.lv, t1.rn,
case when exists (select 1 from t t2 where t1.rn between rn + 1 and rn + 3 and
lv between t1.lv - #variation and t1.lv +#variation) then grp else grp + 1 end
from t t1 join a on
t1.rn = a.rn +1
)
insert #result
select min(time), max(time) from a group by grp
if ##rowcount > 10
begin
set #variation=#variation + .5
goto a
end
select * from #result
Result:
mintime maxtime
2010-01-01 00:15:00.000 2010-01-01 01:45:00.000
2010-01-01 02:00:00.000 2010-01-01 03:00:00.000
2010-01-01 03:15:00.000 2010-01-01 04:00:00.000

Related

Converting GMT to EST in SQL Server

I have a table which stores records for Daylight saving and non-Daylight savings
CREATE TABLE #tmp
(
ID int,
IntervalName nvarchar(100),
StartDate datetime,
EndDate Datetime,
offset numeric(5, 2)
)
INSERT INTO #tmp
VALUES (1, 'EDT', '2022-03-13 07:00:00.000', '2022-11-06 06:00:00.000',-4.00)
INSERT INTO #tmp
VALUES (2, 'EST', '2022-11-06 06:00:00.000', '2023-03-12 07:00:00.000', -5.00)
I have my transactional tables which have Date column in the GMT timezone.
ID DatetimeGMT DatetimeLocal
---------------------------------------------------------
1 2022-11-05 07:00:00.000 2022-11-05 03:00:00.000
2 2022-11-10 06:00:00.000 2023-11-10 01:00:00.000
Now my DatetimeLocal column is calculating the offset hours based on the DatetimeGMT column.
The row with ID = 1 falls under offset -4 and the row with ID = 2 falls under offset -5.
Is there any suggestion how we can achieve this?
If you have the offsets all stored in a table like that, then you just need to JOIN to find the correct one.
eg
drop table if exists #tmp
drop table if exists #tran
go
CREATE TABLE #tmp
(
ID int,
IntervalName nvarchar(100),
StartDate datetime,
EndDate Datetime,
offset numeric(5, 2)
)
INSERT INTO #tmp
VALUES (1, 'EDT', '2022-03-13 07:00:00.000', '2022-11-06 06:00:00.000',-4.00)
INSERT INTO #tmp
VALUES (2, 'EST', '2022-11-06 06:00:00.000', '2023-03-12 07:00:00.000', -5.00)
create table #tran(id int primary key, DateTimeUTC datetime)
insert into #tran(id,DateTimeUTC) values (1,'2022-11-05 07:00:00.000'),(2,'2022-11-10 06:00:00.000')
select t.id, t.DateTimeUTC, dateadd(hour,offset,t.DateTimeUTC) DateTimeLocal, tz.offset
from #tran t
join #tmp tz
on t.DateTimeUTC >= tz.StartDate
and t.DateTimeUTC < tz.EndDate
outputs
id DateTimeUTC DateTimeLocal offset
----------- ----------------------- ----------------------- ---------------------------------------
1 2022-11-05 07:00:00.000 2022-11-05 03:00:00.000 -4.00
2 2022-11-10 06:00:00.000 2022-11-10 01:00:00.000 -5.00
SQL Server 2016 and later have the offsets built-in, so you can write queries like
select t.id,
t.DateTimeUTC,
cast(t.DateTimeUTC at time zone 'UTC' at time zone 'EASTERN STANDARD TIME' as datetime) DateTimeLocal
from #tran t

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

T-SQL max date and min date between two date for each day

First, thanks for your time and your help!
I have two tables:
Table 1
PersId name lastName city
---------------------------------------
1 John Smith Tirana
2 Leri Nice Tirana
3 Adam fortsan Tirana
Table 2
Id PersId salesDate
--------------------------------------------
1 1 2017-01-22 08:00:40 000
2 2 2017-01-22 09:00:00 000
3 1 2017-01-22 10:00:00 000
4 1 2017-01-22 20:00:00 000
5 3 2017-01-15 09:00:00 000
6 1 2017-01-21 09:00:00 000
7 1 2017-01-21 10:00:00 000
8 1 2017-01-21 18:55:00 000
I would like to see the first recent sales between two dates according to each city for each day I want to bring it empty if I do not have a sale
SalesDate > '2017-01-17 09:00:00 000'
and SalesDate < '2017-01-23 09:00:00 000'
Table 2, id = 5 because the record is not in the specified date range
If I wanted my results to look like
Id PersId MinSalesDate MaxSalesDate City Date
-----------------------------------------------------------------------------
1 1 2017-01-22 08:00:40 000 2017-01-22 20:00:00 000 Tirana 2017-01-22
2 2 2017-01-22 09:00:00 000 null Tirana 2017-01-22
3 3 null null Tirana 2017-01-22
4 1 2017-01-21 09:00:00 000 2017-01-21 18:55:00 000 Tirana 2017-01-21
5 2 null null Tirana 2017-01-21
6 3 null null Tirana 2017-01-21
7 1 null null Tirana 2017-01-20
8 2 null null Tirana 2017-01-20
9 3 null null Tirana 2017-01-20
vb.....
It works for 1 day, but it does not work every day for 2 days
SELECT
T2.Id, T1.PersId, T2.MIN_salesDate, T2.MAX_salesDate, T1.City
FROM Table1 T1
LEFT JOIN
(
SELECT MIN(Id) as Id, PersId, MIN(salesDate) as MIN_salesDate, MAX(salesDate) as MAX_salesDate
FROM
(
SELECT
*
,ROW_NUMBER() OVER (PARTITION BY PersId ORDER BY salesDate ASC) as RNKMIN
,ROW_NUMBER() OVER (PARTITION BY PersId ORDER BY salesDate DESC) as RNKMAX
FROM Table2 T2
WHERE salesDate Between '2017-01-17 09:00:00 000' And '2017-01-23 09:00:00 000'
) temp
WHERE RNKMIN = 1 or RNKMAX = 1
GROUP BY PersId
) T2
on T1.PersId = T2.PersId
Try this
DECLARE #Table1 TABLE(
PersId INT,
name NVARCHAR(50),
city NVARCHAR(50)
)
DECLARE #Table2 TABLE(
Id INT,
PersId INT,
salesDate NVARCHAR(50)
)
INSERT INTO #Table1 VALUES(1, 'John', 'Tirana')
INSERT INTO #Table1 VALUES(2, 'Leri', 'Tirana')
INSERT INTO #Table1 VALUES(3, 'Adam', 'Tirana')
INSERT INTO #Table2 VALUES(1, 1, '2017-01-22 08:00:40')
INSERT INTO #Table2 VALUES(2, 2, '2017-01-22 09:00:00')
INSERT INTO #Table2 VALUES(3, 1, '2017-01-22 10:00:00')
INSERT INTO #Table2 VALUES(4, 1, '2017-01-22 20:00:00')
INSERT INTO #Table2 VALUES(5, 3, '2017-01-15 09:00:00')
INSERT INTO #Table2 VALUES(6, 1, '2017-01-21 09:00:00')
INSERT INTO #Table2 VALUES(7, 1, '2017-01-21 10:00:00')
INSERT INTO #Table2 VALUES(8, 1, '2017-01-21 18:55:00')
SELECT T1.PersId, GroupTable.MinSalesDate, GroupTable.MaxSalesDate, T1.city
FROM #Table1 AS T1
LEFT JOIN
(SELECT max(salesDate) as 'MaxSalesDate', CASE WHEN min(salesDate) <> max(salesDate) THEN min(salesDate) ELSE NULL END AS 'MinSalesDate', PersId
FROM #Table2
WHERE salesDate > '2017-01-17 09:00:00' and SalesDate < '2017-01-23 09:00:00'
GROUP BY DATEPART(day, salesDate) , PersId) AS GroupTable
ON T1.PersId = GroupTable.PersId
Result:
Please try this - Please let us know if you require any modification.
SELECT a.PersId, MIN(salesDate) MinSalesDate , CASE WHEN MIN(salesDate) = MAX(salesDate)
THEN NULL ELSE MAX(salesDate) END MaxSalesDate , a.city FROM Table1 a
FULL JOIN Table2 b ON a.PersId = b.PersId
AND SalesDate > '2017-01-17 09:00:00' and SalesDate < '2017-01-23 09:00:00'
WHERE a.PersId IS NOT NULL
GROUP BY a.PersId,a.city,CAST(salesDate AS DATE)
ORDER BY a.PersId
OUTPUT
PersId MinSalesDate MaxSalesDate city
----------- ----------------------- ----------------------- ----------
1 2017-01-22 08:00:40.000 2017-01-22 20:00:00.000 Tirana
2 2017-01-22 09:00:00.000 NULL Tirana
3 NULL NULL Tirana
1 2017-01-21 09:00:00.000 2017-01-21 18:55:00.000 Tirana
(4 rows affected)
I have updated your query also. Please see.
SELECT
T2.Id, T1.PersId, T2.MIN_salesDate, T2.MAX_salesDate, T1.City
FROM Table1 T1
LEFT JOIN
(
SELECT MIN(Id) as Id, PersId, MIN(salesDate) as MIN_salesDate, MAX(salesDate) as MAX_salesDate
FROM
(
SELECT
*
,ROW_NUMBER() OVER (PARTITION BY PersId ORDER BY salesDate ASC) as RNKMIN
,ROW_NUMBER() OVER (PARTITION BY PersId ORDER BY salesDate DESC) as RNKMAX
FROM Table2 T2
WHERE salesDate Between '2017-01-17 09:00:00' And '2017-01-23 09:00:00'
) temp
WHERE RNKMIN = 1 or RNKMAX = 1
GROUP BY PersId,CAST(salesDate AS DATE)
) T2
on T1.PersId = T2.PersId
OUTPUT from your query
Id PersId MIN_salesDate MAX_salesDate City
----------- ----------- ----------------------- ----------------------- ----------
6 1 2017-01-21 09:00:00.000 2017-01-21 09:00:00.000 Tirana
4 1 2017-01-22 20:00:00.000 2017-01-22 20:00:00.000 Tirana
2 2 2017-01-22 09:00:00.000 2017-01-22 09:00:00.000 Tirana
NULL 3 NULL NULL Tirana
(4 rows affected)

T-SQL to Group time interval change by date range in sql server

The original table has the column Timestamp with Interval
Interval: difference in minute between the current and previous Timestamp when sorted by Timestamp itself
Timestamp Interval(InMinute)
2016-12-31 00:28:00 NULL
2016-12-31 00:29:00 1
2016-12-31 00:30:00 1
2016-12-31 00:45:00 15
2016-12-31 01:00:00 15
2016-12-31 01:15:00 15
2016-12-31 01:16:00 1
2016-12-31 01:17:00 1
2016-12-31 01:18:00 1
2016-12-31 01:19:00 1
I want to detect a time interval change using T-SQL and produce the output
StartDate EndDate Interval
2016-12-31 00:28:00 2016-12-31 00:30:00 1
2016-12-31 00:30:00 2016-12-31 01:15:00 15
2016-12-31 01:15:00 2016-12-31 01:19:00 1
I wanted to tell for how long an Interval stayed the same. The second row says that from 2016-12-31 00:30:00 to 2016-12-31 01:15:00, the Interval stayed the same i.e. 15. But then it changed back to 1 after 2016-12-31 01:15:00
Try the below:
declare #tbl table
(datec datetime)
insert into #tbl
select '2016-12-31 00:29:00'
union all
select '2016-12-31 00:30:00'
union all
select '2016-12-31 00:45:00'
union all
select '2016-12-31 01:00:00'
union all
select '2016-12-31 01:01:00'
union all
select '2016-12-31 01:02:00'
select datec,nextdatec,datediff(MINUTE,datec,nextdatec) as diff from (
select datec,LEAD(datec) over(order by datec) as nextdatec from #tbl
) tbl
where datediff(MINUTE,datec,nextdatec) is not null
This will work
CREATE TABLE ##T1 (DATE_STAMP DATETIME)
INSERT INTO ##T1 VALUES ('12-31-2016 00:29:00')
INSERT INTO ##T1 VALUES ('12-31-2016 00:30:00')
INSERT INTO ##T1 VALUES ('12-31-2016 00:45:00')
INSERT INTO ##T1 VALUES ('12-31-2016 01:00:00')
INSERT INTO ##T1 VALUES ('12-31-2016 01:01:00')
INSERT INTO ##T1 VALUES ('12-31-2016 01:02:00')
SELECT ROW_NUMBER() OVER(ORDER BY DATE_STAMP) ID, * INTO ##T2 FROM ##T1
SELECT A.DATE_STAMP START_DATE
,B.DATE_STAMP END_DATE
,DATEDIFF(MINUTE, A.DATE_STAMP, B.DATE_STAMP) INTERVAL
FROM ##T2 A
INNER JOIN ##T2 B
ON B.ID = A.ID + 1
DROP TABLE ##T1, ##T2
Answered on Stackexchange
Fiddle Link

How do I add time datatype column in SQL server

I have a table in sql server 2012,with column named Duration as Time datatype.i want to update this column base on difference of dates, by adding the difference to this duration column.how can I do this in SP.
ID StartDate EndDate Duration
1 2017-02-27 09:10:35 2017-02-27 09:25:35 00:15
2 2017-02-27 09:26:35 2017-02-27 09:36:35 00:25
Durtion always less than 24 hours.
One method is:
update t
set duration = cast(dateadd(ms, datediff(ms, startdate, enddate), 0) as time);
This is an easy one. Just use a simple arithmetic operation:
DECLARE #TABLE TABLE (Start DATETIME, Finish DATETIME, Duration TIME);
INSERT INTO #TABLE VALUES ('02/28/2017 08:00','02/28/2017 08:30','');
INSERT INTO #TABLE VALUES ('02/28/2017 09:00','02/28/2017 09:40','');
INSERT INTO #TABLE VALUES ('02/28/2017 10:02','02/28/2017 11:53','');
INSERT INTO #TABLE VALUES ('02/28/2017 11:56','02/28/2017 12:45','');
INSERT INTO #TABLE VALUES ('02/28/2017 13:45','02/28/2017 23:59','');
UPDATE #TABLE
SET Duration = Finish - Start;
SELECT * FROM #TABLE;
Returns:
Start Finish Duration
---------------------------------------------------------
28/02/2017 08:00:00 28/02/2017 08:30:00 00:30:00
28/02/2017 09:00:00 28/02/2017 09:40:00 00:40:00
28/02/2017 10:02:00 28/02/2017 11:53:00 01:51:00
28/02/2017 11:56:00 28/02/2017 12:45:00 00:49:00
28/02/2017 13:45:00 28/02/2017 23:59:00 10:14:00
The only caveat here being that they need to be on the same day. You explicitly stated that the duration is never more than one day, so that should be fine.
If you want to add the result to the original value of Duration, then you would just add it on...
INSERT INTO #TABLE VALUES ('02/27/2017 08:00','02/28/2017 08:30','00:15');
INSERT INTO #TABLE VALUES ('02/28/2017 09:00','02/28/2017 09:40','00:14');
INSERT INTO #TABLE VALUES ('02/28/2017 10:02','02/28/2017 11:53','00:13');
INSERT INTO #TABLE VALUES ('02/28/2017 11:56','02/28/2017 12:45','02:16');
INSERT INTO #TABLE VALUES ('02/28/2017 13:45','02/28/2017 23:59','00:17');
UPDATE #TABLE
SET Duration = Duration + (Finish - Start);
Returns:
Start Finish Duration
---------------------------------------------------------
27/02/2017 08:00:00 28/02/2017 08:30:00 00:45:00
28/02/2017 09:00:00 28/02/2017 09:40:00 00:54:00
28/02/2017 10:02:00 28/02/2017 11:53:00 02:04:00
28/02/2017 11:56:00 28/02/2017 12:45:00 03:05:00
28/02/2017 13:45:00 28/02/2017 23:59:00 10:31:00
UPDATE [TABLE] SET [DURATION] = CONVERT(varchar(5),DATEADD(minute, DATEDIFF(MINUTE, StartDate, EndDate), 0), 114);
None of the other answers attempt to SUM the duration which is what you expect.
DECLARE #TABLE TABLE (ID INT, StartTime DATETIME, EndTime DATETIME, Duration TIME);
INSERT INTO #TABLE VALUES (1, '02/28/2017 01:00','02/28/2017 06:30','');
INSERT INTO #TABLE VALUES (2, '02/28/2017 09:00','02/28/2017 23:40','');
INSERT INTO #TABLE VALUES (3, '03/01/2017 10:02','03/01/2017 21:53','');
UPDATE t
SET Duration=
CONVERT(TIME,
(
SELECT DATEADD(ms, SUM(DATEDIFF(ms, '00:00:00.000', EndTime - StartTime)), '00:00:00.000')
FROM #TABLE it
WHERE it.EndTime<= t.EndTime
)
)
FROM #TABLE t;
SELECT * FROM #TABLE;