Reputation: 399
I am trying to create a table that shows Operator Shifts be combining rows w Operator logons and logoffs. As there are multiple stations and operators I need to select the next row based on the operator not just the next value. For example, when separating the joined queries in the below the last logon time will be row 329 and the logoff time will be row 408.
Logon = 1 and Logoff = 0
select
A.Operator,
A.Station,A.[TIME] AS "Logon",
B.[TIME] AS "Logoff"
from (SELECT
[Operator],
[TIME],
[Station],
ROW_NUMBER() OVER (ORDER BY [TIME], [Operator], Station) AS RowNumber
FROM
shiftstagenew
WHERE [ON-OFF] = '0'
AND [Operator] = 'Operator1') A
JOIN
(SELECT
[Operator],
[TIME],
[Station],
ROW_NUMBER() OVER (ORDER BY [TIME], [Operator], Station) AS RowNumber
FROM shiftstagenew WHERE [ON-OFF] = '1'
AND [Operator] = 'Operator1') B
ON (
A.RowNumber = B.RowNumber
AND
A.Operator = B.Operator
AND
A.Station = B.Station)
I've updated the query and coming closer
select A.Operator, A.Station,B.[TIME] AS "Logon", A.[TIME] AS "Logoff"
from (SELECT [TIME], [Operator], [Station], ROW_NUMBER() OVER (PARTITION
BY
[Operator], [Station] ORDER BY [Time], Station) AS RowNumber
FROM
shiftstagenew WHERE [ON-OFF] = '1') A
JOIN
(SELECT [Time],[Operator], [Station], ROW_NUMBER() OVER (PARTITION BY
[Operator], [Station] ORDER BY [Time], Station) AS RowNumber
FROM shiftstagenew WHERE [ON-OFF] = '0') B
ON (A.Operator=B.Operator AND A.Station=B.Station AND A.RowNumber=B.RowNumber)
Query Results:
Operator Station Logoff Logon
Vitemeus 102 2019-07-07 08:15:19.380 2019-05-27 17:39:06.550
Vitemeus 102 2019-07-07 07:23:54.790 2019-05-27 14:50:13.687
Vitemeus 102 2019-07-07 03:45:46.890 2019-05-27 11:56:54.903
Vitemeus 102 2019-07-07 03:44:28.267 2019-05-24 23:52:49.313
Vitemeus 102 2019-07-07 03:08:16.343 2019-05-20 19:30:11.010
As you can see there are the logoff isn't following the last logon
OFF
2019-07-07 08:15:19.380 Vitemeus 102 445
2019-07-07 07:23:54.790 Vitemeus 102 444
2019-07-07 03:45:46.890 Vitemeus 102 443
2019-07-07 03:44:28.267 Vitemeus 102 442
2019-07-07 03:08:16.343 Vitemeus 102 441
2019-07-07 02:00:09.757 Vitemeus 102 440
2019-07-07 00:37:30.610 Vitemeus 102 439
2019-07-06 13:16:02.330 Vitemeus 102 438
2019-07-06 12:00:19.157 Vitemeus 102 437
ON
2019-07-07 08:02:02.500 Vitemeus 102 498
2019-07-07 06:52:34.303 Vitemeus 102 497
2019-07-07 03:44:42.427 Vitemeus 102 496
2019-07-07 03:25:28.957 Vitemeus 102 495
2019-07-07 02:52:40.210 Vitemeus 102 494
2019-07-07 01:45:00.373 Vitemeus 102 493
2019-07-07 00:32:39.800 Vitemeus 102 492
For those asking for the table structure(ON-OFF is either 0 or 1):
CREATE TABLE [dbo].[ShiftStageNEW](
[ON-OFF] [nvarchar](1) NULL,
[Time] [datetime] NULL,
[Station] [nvarchar](3) NULL,
[Action] [nvarchar](4) NULL,
[Operator] [varchar](8) NULL,
[Data] [nvarchar](900) NULL,
[Translation] [int] NULL,
[LogTime] [bigint] NULL,
[MessageId] [nvarchar](256) NULL
) ON [PRIMARY]
Upvotes: 0
Views: 185
Reputation: 5083
You should look at the LAG
function:
SELECT
[Year] = YEAR([OrderDate])
,[Sales Amount] = SUM([SalesAmount])
,[Sales Amount Previous Year] = LAG(SUM([SalesAmount])) OVER (ORDER BY YEAR([OrderDate]))
FROM [dbo].[FactResellerSales]
GROUP BY YEAR([OrderDate])
ORDER BY [Year];
source: https://www.mssqltips.com/sqlservertutorial/9127/sql-server-window-functions-lead-and-lag/
Also see my question here that matches your requirement: Find next record where status field is different from current
Upvotes: 1
Reputation: 2222
Common table expression should help you with what you want to achieve.
But the sequencing of the row numbers seems a little fishy.
Added partitioning to the sequencing. You can stick to your original if that's what you need.
WITH LOGON AS (
SELECT
[Operator],
[TIME],
[Station],
ROW_NUMBER() OVER (PARTITION BY [Operator], Station ORDER BY [TIME]) AS RowNumber
FROM
shiftstagenew
WHERE
[ON-OFF] = '0'
AND [Operator] = 'Operator1'
),
LOGOFF AS (
SELECT
[Operator],
[TIME],
[Station],
ROW_NUMBER() OVER (PARTITION BY [Operator], Station ORDER BY [TIME]) AS RowNumber
FROM
shiftstagenew
WHERE
[ON-OFF] = '1'
AND [Operator] = 'Operator1'
)
select
LOGON.Operator,
LOGON.Station,
LOGON.[TIME] AS "Logon",
LOGOFF.[TIME] AS "Logoff"
FROM LOGON LEFT JOIN LOGOFF
ON (
LOGON.RowNumber = LOGOFF.RowNumber
AND
LOGON.Operator = LOGOFF.Operator
AND
LOGON.Station = LOGOFF.Station)
Upvotes: 0