SQL query to group by day and calculate elapsed time (aggregating rows) - sql

I'm using SQL Server 2008 and looking how to create such a query:
I have a table:
Username nvarchar(50), LogDate datetime
Test1, 2012.01.01 00:00:00
Test2, 2012.01.01 00:00:02
Test1, 2012.01.01 00:00:05
Test3, 2012.01.01 00:00:06
Test1, 2012.01.02 00:01:01
Test2, 2012.01.02 00:02:50
Test1, 2012.01.02 00:01:01
Every few seconds users send updates to insert current datetime with his username in to the log table. I need to calculate how much hours users were "online" every day.
I assume query should sum DateDiff between two rows with the same username grouped by day.
I tried using rank, but haven't got what I want.
Thank you for your help in advance.

You can extract the date part of the DateTime and group by the UserName to use DateDiff on the MIN / MAX Values:
Table and Data Setup:
create table UserLog (Username nvarchar(50), LogDate DateTime);
insert into UserLog Values('Test1', '2012-01-01 00:00:00');
insert into UserLog Values('Test2', '2012-01-01 00:00:02');
insert into UserLog Values('Test1', '2012-01-01 00:00:05');
insert into UserLog Values('Test3', '2012-01-01 00:00:06');
insert into UserLog Values('Test3', '2012-01-01 00:01:26');
insert into UserLog Values('Test3', '2012-01-01 00:03:22');
insert into UserLog Values('Test3', '2012-01-01 00:05:42');
insert into UserLog Values('Test3', '2012-01-01 00:00:06');
insert into UserLog Values('Test1', '2012-01-02 00:01:01');
insert into UserLog Values('Test2', '2012-01-02 00:02:50');
insert into UserLog Values('Test1', '2012-01-02 00:01:01');
Then you can SELECT as follows:
select UserName, CAST(LogDate AS DATE) as BusinessDay,
MIN(LogDate) as FirstLogEntry, MAX(LogDate) as LastLogEntry,
DATEDIFF(second,MIN(LogDate), MAX(LogDate)) as ElapsedSeconds
FROM UserLog
GROUP BY Username, CAST(LogDate AS DATE)
This will yield the following results and you can calculate hours from the seconds. I showed seconds based on your sample data with test3 user expanded:
UserName BusinessDay FirstLogEntry LastLogEntry ElapsedSeconds
-------- ----------- ----------------------- ----------------------- --------------
Test1 2012-01-01 2012-01-01 00:00:00.000 2012-01-01 00:00:05.000 5
Test2 2012-01-01 2012-01-01 00:00:02.000 2012-01-01 00:00:02.000 0
Test3 2012-01-01 2012-01-01 00:00:06.000 2012-01-01 00:05:42.000 336
Test1 2012-01-02 2012-01-02 00:01:01.000 2012-01-02 00:01:01.000 0
Test2 2012-01-02 2012-01-02 00:02:50.000 2012-01-02 00:02:50.000 0

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

SQL Server copy muptiple rows of same table changing only date of a datetime column

I need to copy all rows of a table, changing only the date part of the Datetime. The query I've been testing in sqlfiddle, returns record count of 0, and obviously the #newDate + SameTime isn't part of the query, but I put it there so you know what I want to do.
CREATE TABLE Games
(
[Id] int IDENTITY(1, 1) PRIMARY KEY,
[GameTypeId] int,
[DateCreated] datetime,
[DateTime] datetime,
[Location] int
);
INSERT INTO Games ([GameTypeId], [DateCreated], [DateTime], [Location])
VALUES ('1', GETDATE(), '8/21/2021 8:00:00', '1'),
('2', GETDATE(), '8/21/2021 9:00:00', '1'),
('2', GETDATE(), '8/21/2021 10:00:00', '1');
The query I'm testing to copy the rows but is not working:
INSERT INTO Games (GameTypeId, DateCreated, DateTime, Location)
SELECT
GameTypeId, GETDATE(), #newDate + SameTime, Location
FROM
Games
WHERE
CONVERT(date, DateTime) = '8/21/2021'
The results from the initial insert:
Id GameTypeID DateCreated DateTime Location
--------------------------------------------------------------
1 1 8/15/2021 8/21/2021 8:00:00 1
2 1 8/15/2021 8/21/2021 9:00:00 1
3 1 8/15/2021 8/21/2021 10:00:00 1
And after the copy rows query, the results I want (but can't get). I want to copy everything to a new row, except the date only needs to change. The time stays the same:
4 1 8/20/2021 8/28/2021 8:00:00 1
5 1 8/20/2021 8/28/2021 9:00:00 1
6 1 8/20/2021 8/28/2021 10:00:00 1
You can use date arithmetic:
INSERT INTO Games (GameTypeId, DateCreated, DateTime, Location)
SELECT GameTypeId, DATEADD(day, 5, DateCreated),
DATEADD(day, 7, DateTime), location
FROM Games
WHERE CONVERT(date, DateTime) = '2021-08-21'

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;

How to compare date in SQL Server 2008

Here I need to compare date using SQL Server 2008. I want show details of the table if the specific date appears more than one time.
Example:
create table datetest
(
columnx nvarchar(10),
columny nvarchar(10),
coldate date,
coltime datetime
)
insert into datetest values('a123','b123','2014-01-01','01:05:00.000');
insert into datetest values('a123','b456','2014-01-01','02:15:00.000');
insert into datetest values('a123','b789','2014-01-01','03:25:00.000');
insert into datetest values('a321','b321','2014-02-03','10:05:00.000');
insert into datetest values('a243','b243','2014-03-04','11:05:00.000');
insert into datetest values('a243','b243','2014-03-04','12:05:00.000');
insert into datetest values('a243','b243','2014-03-04','12:05:00.000');
Now I need to show only that records whose dates are greater than one appear in the table.
Expected result:
columnx columny coldate coltime
-------------------------------------------------------
a123 b123 2014-01-01 1900-01-01 01:05:00.000
a123 b456 2014-01-01 1900-01-01 02:15:00.000
a123 b789 2014-01-01 1900-01-01 03:25:00.000
a243 b243 2014-03-04 1900-01-01 11:05:00.000
a243 b243 2014-03-04 1900-01-01 12:05:00.000
a243 b243 2014-03-04 1900-01-01 12:05:00.000
My attempt:
select *
from datetest
where coldate = '2014-01-01' or coldate = '2014-03-04';
Note: But this is not the right way for the large records to check.
try like this
select * from datetest
where coldate in (select coldate from
datetest group by coldate having count(*) > 1)
DEMO

Finding Max and Min Times

I want to display max time and min time for a day in grid control using Visual Basic from a SQL Server database. My data currently looks like this:
UserID UserName Date Time
------------------------------------------
1 Shanks 30/1/2009 10:11:22
1 Shanks 30/1/2009 10:15:22
1 Shanks 30/1/2009 12:15:22
1 Shanks 30/1/2009 13:15:22
I need the output like this:
1 Shanks 30/1/2009 10:11:22 13:15:22
My table structure is:
UserID integer,
UserName varchar(20),
[Date] datetime,
[Time] datetime
How can I get that output from my data?
Is this what you're looking for?
SELECT UserID,
UserName,
Date,
MIN([Time]) AS MinTime,
MAX([Time]) AS MaxTime,
FROM Users
GROUP BY UserID, UserName, [Date]
SELECT
UserID,
UserName,
[Date],
MIN([Time]),
MAX([Time])
FROM
Table
GROUP BY
UserID,
UserName,
[Date]
Tested and working correctly with the following
DECLARE #Table TABLE (UserID INT,UserName VARCHAR(25),[Date] DATETIME,[Time] DATETIME)
INSERT INTO #Table VALUES(1, 'Shanks', '30 JAN 2009', '10:11:22');
INSERT INTO #Table VALUES(1, 'Shanks', '30 JAN 2009', '10:15:22');
INSERT INTO #Table VALUES(1, 'Shanks', '30 JAN 2009', '12:15:22');
INSERT INTO #Table VALUES(1, 'Shanks', '30 JAN 2009', '13:15:22');
INSERT INTO #Table VALUES(2, 'Shilpa', '3 JAN 2009', '10:11:22');
INSERT INTO #Table VALUES(2, 'Shilpa', '3 JAN 2009', '11:15:22');
INSERT INTO #Table VALUES(2, 'Shilpa', '3 JAN 2009', '12:15:22');
INSERT INTO #Table VALUES(2, 'Shilpa', '3 JAN 2009', '17:15:22');
SELECT
UserID,
UserName,
[Date],
MIN([Time]),
MAX([Time])
FROM
#Table
GROUP BY
UserID,
UserName,
[Date]
Results in
UserID UserName Date
----------- ------------------------- ----------------------- ----------------------- -----------------------
1 Shanks 2009-01-30 00:00:00.000 1900-01-01 10:11:22.000 1900-01-01 13:15:22.000
2 Shilpa 2009-01-03 00:00:00.000 1900-01-01 10:11:22.000 1900-01-01 17:15:22.000