I have a table which only which stores the login and logout date against a user along with their time and their datatype is datetime
.
The dates are stored in the format 2021-12-17 14:05:25.597
.
I am able to get the total time duration between the login and logout date but I need to sum all the rows across a particular user against a date.
Here is some sample data:
Sno USERID Name LoginDateAndTime LogOutDateAndTime TimeDuration Total
-----------------------------------------------------------------------------------
1 222 abc 17 Dec 2021 1:40PM 17 Dec 2021 1:40PM 0:0:9
2 222 abc 17 Dec 2021 2:05PM 17 Dec 2021 3:07PM 1:2:4
3 444 xyz 18 Dec 2021 3:37PM 18 Dec 2021 3:37PM 0:0:6
4 444 xyz 16 Dec 2021 1:51PM 16 Dec 2021 2:22PM 0:30:24
5 444 xyz 16 Dec 2021 10:17PM 16 Dec 2021 10:18PM 0:1:20
Here is my query:
SELECT
u.userid, u.Name,
CONVERT(varchar, la.loginDate, 106) ' ' LTRIM(RIGHT(CONVERT(VARCHAR(20), la.loginDate, 100), 7)) AS LoginDateAndTime,
CONVERT(varchar, la.logoutDate,106) ' ' LTRIM(RIGHT(CONVERT(VARCHAR(20), la.logoutDate, 100), 7)) AS LogOutDateAndTime,
CONVERT(varchar(5), DATEDIFF(s, loginDate, logoutDate) / 3600) ':'
CONVERT(varchar(5), DATEDIFF(s, loginDate, logoutDate) % 3600 / 60) ':'
CONVERT(varchar(5), (DATEDIFF(s, loginDate, logoutDate) % 60)) AS 'TimeDuration',
FROM
login la
LEFT JOIN
users u ON u.userid = la.id
Now I want to show a new column that sums up the hours and minutes across same Ids and same date.
I did multiple searches but I am still confused.
For example:
Against
Id = 222
there are two entries with same date so the total would be0:0:9
plus1:2:4
which is1:2:13
Against
Id = 444
there are three entries with two different dates so against Sno3
The total would be same that is0:0:6
and against Sno4
and5
these two would add i.e0:30:24
and0:1:20
.
How can I achieve this?Anyone can help me with this? Its quite complicated
CodePudding user response:
based on your fiddles, i also created one, but currently im unable to comment, so posted it as an answer:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=3980a6b2eec812d82fe9ed43339981c2
--with-clause begins
--pre as (...) is the first query within the with-clause
with pre as (
select
USERID,
Name,
CAST(loginDate AS date) AS LoginData,
convert(varchar,loginDate,106) ' ' LTRIM(RIGHT(CONVERT(VARCHAR(20),loginDate, 100), 7)) as LoginDateAndTime,
convert(varchar,logoutDate,106) ' ' LTRIM(RIGHT(CONVERT(VARCHAR(20),logoutDate, 100), 7)) as LogOutDateAndTime,
convert(varchar(5),DateDiff(s, loginDate, logoutDate)/3600) ':' convert(varchar(5),DateDiff(s, loginDate, logoutDate)600/60) ':' convert(varchar(5),(DateDiff(s, loginDate, logoutDate)`)) as 'Time Duration Of Login [hh:mm:ss]'
from
login
),
--total as (...) is the second query within the with-clause
total as (
SELECT
userid,
Name,
CAST(loginDate AS date) AS LoginData,
CONVERT(varchar(5), SUM(DATEDIFF(s, loginDate, logoutDate)) / 3600) ':'
CONVERT(varchar(5), SUM(DATEDIFF(s, loginDate, logoutDate)) % 3600 / 60) ':'
CONVERT(varchar(5), SUM(DATEDIFF(s, loginDate, logoutDate)) % 60) AS TotalDuration
FROM
login
GROUP BY
userid,
Name,
CAST(loginDate AS date)
)
--with-clause ends
select
pre.*,
total.totalduration
from
pre
join
total
on
pre.userid = total.userid
and total.LoginData = pre.loginData
please refer to https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver15 for detailed explanation
in short words, with
-clauses are used to organize and simplyfy complex sql-statements, for example: to get rid of sub-queries with select
-statements; so with
-clauses 'make sql-statements easier to read'
therefore the with
-clause provides one ore more temporary named resultset(s), also known as common table expression (CTE), that are defined within the execution scope of a single select
, insert
, update
, delete
or merge
statement
in my posted statement, i combined your query (pre) and @Charlieface s query (total)
@Charlieface s query (total) sum
s up the loginduration for each userid, name and logindate.
if i got you right, you wanted to achieve a query, that returns all rows from login-table expanded by the total login-duration per date and per user (id and name)
thats what the statement above does.
if i got you wrong and you want to achieve a query that return all rows from login-table expanded by the total login-duration overall dates per user (id and name), i customized the statement as follows, my customization - in relation to the statement above - are the commented lines within the statement:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d2240f4ce7364ceccbcc8eec88dfada6
with pre as (
select
USERID,
Name,
--CAST(loginDate AS date) AS LoginData,
convert(varchar,loginDate,106) ' ' LTRIM(RIGHT(CONVERT(VARCHAR(20),loginDate, 100), 7)) as LoginDateAndTime,
convert(varchar,logoutDate,106) ' ' LTRIM(RIGHT(CONVERT(VARCHAR(20),logoutDate, 100), 7)) as LogOutDateAndTime,
convert(varchar(5),DateDiff(s, loginDate, logoutDate)/3600) ':' convert(varchar(5),DateDiff(s, loginDate, logoutDate)600/60) ':' convert(varchar(5),(DateDiff(s, loginDate, logoutDate)`)) as 'Time Duration Of Login [hh:mm:ss]'
from
login
),
total as (
SELECT
userid,
Name,
--CAST(loginDate AS date) AS LoginData,
CONVERT(varchar(5), SUM(DATEDIFF(s, loginDate, logoutDate)) / 3600) ':'
CONVERT(varchar(5), SUM(DATEDIFF(s, loginDate, logoutDate)) % 3600 / 60) ':'
CONVERT(varchar(5), SUM(DATEDIFF(s, loginDate, logoutDate)) % 60) AS TotalDuration
FROM
login
GROUP BY
userid,
Name
--,
--CAST(loginDate AS date)
)
select
pre.*,
total.totalduration
from
pre
join
total
on
pre.userid = total.userid
--and total.LoginData = pre.loginData
CodePudding user response:
Looks like you just need to group by user ID and date.
It's unclear why you have a
LEFT JOIN
here, why isn't it anINNER
SELECT
times.userid,
times.Name,
times.LoginDate,
CONVERT(varchar(5), TotalDurationS / 3600) ':'
CONVERT(varchar(5), TotalDurationS % 3600 / 60) ':'
CONVERT(varchar(5), TotalDurationS % 60) AS TotalDuration
FROM
(
SELECT
u.userid,
u.Name,
CAST(la.loginDate AS date) AS LoginDate,
SUM(DATEDIFF(s, loginDate, logoutDate)) AS TotalDurationS
FROM login la
JOIN users u ON u.userid = la.id
GROUP BY
u.userid,
u.Name,
CAST(la.loginDate AS date)
) times;
- We begin by grouping by
userid
and the date (which we get by castingas date
) - Then we get the
SUM
of theDATEDIFF
calculation - We then format it as a time