I receive data from a counter, and I want to create a report that print how much was incremented per hour.
I made this query, but I couldn't do a SELECT from 0 to 23 Hours
SELECT [COLUMN_A],
[COLUMN_B],
[COLUMN_A] - [COLUMN_B] AS TOTAL
FROM (
(SELECT MAX([_Counter]) AS COLUMN_A
FROM [DADOS].[dbo].Table_Producao]
WHERE DatePart(HOUR, _TimeStamp)=9)AS PART_A
CROSS JOIN(SELECT MAX([_Count]) AS COLUMN_B
FROM [DADOS].[dbo].[Table_Producao]
WHERE DatePart(HOUR, _TimeStamp)=8)AS PART_B
)
What a I have:
_TimeStamp _Counter
2015-02-03 14:00:00.000 2
2015-02-03 14:59:00.000 15
2015-02-03 15:00:00.000 17
2015-02-03 15:30:00.000 30
2015-02-03 15:59:00.000 42
2015-02-03 16:00:00.000 43
2015-02-03 16:30:00.000 50
2015-02-03 16:59:00.000 59
2015-02-03 17:00:00.000 61
2015-02-03 17:30:00.000 70
2015-02-03 17:50:00.000 82
2015-02-03 18:00:00.000 86
2015-02-03 18:30:00.000 90
2015-02-03 18:59:00.000 99
2015-02-03 19:00:00.000 102
2015-02-03 19:30:00.000 115
2015-02-03 19:59:00.000 124
2015-02-03 20:00:00.000 126
2015-02-03 20:30:00.000 137
2015-02-03 20:59:00.000 145
2015-02-03 21:00:00.000 147
What I want:
_TimeStamp _Counter
14h 17
15h 27
16h 17
17h 23
18h 17
19h 25
20h 21
21h 2
Any ideas? please
try this.
SELECT Cast(Datepart(hh, [_timestamp]) AS VARCHAR(3))+ 'h',
Sum(_counter)
FROM your_result
GROUP BY Cast(Datepart(hh, [_timestamp]) AS VARCHAR(3))+ 'h',
Cast(_timestamp AS DATE)
I solved my qestion with this query:
WITH QUERY1 AS
(SELECT MAX(_Counter) AS MAX_1, Datepart(hh, [TimeStamp]) AS _TIMESTAMP1
FROM Table
WHERE Cast(DatePart(hh, TimeStamp)AS int) IN (SELECT Cast(Datepart(hh, [TimeStamp]) AS int)
FROM Table
WHERE TimeStamp>=CAST('<%DataQuery%>'+' 00:00:00.000' AS DATETIME) AND TimeStamp<=CAST('<%DataQuery%>'+' 23:59:59.999' AS DATETIME)
)
GROUP BY Cast(Datepart(hh, [TimeStamp])AS int)),
QUERY2 AS
(SELECT MAX(_Counter) AS MAX_2, Datepart(hh, [TimeStamp]) AS _TIMESTAMP2
FROM PLASCAR_DADOS.dbo.Table_Producao
WHERE Cast(DatePart(hh, TimeStamp)AS int) IN (SELECT Cast(Datepart(hh, [TimeStamp]) AS int)+1
FROM Table
WHERE TimeStamp>=CAST('<%DataQuery%>'+' 00:00:00.000' AS DATETIME) AND TimeStamp<=CAST('<%DataQuery%>'+' 23:59:59.999' AS DATETIME)
)
GROUP BY Cast(Datepart(hh, [TimeStamp])AS int))
SELECT _TIMESTAMP1, MAX_2-MAX_1 AS TOTAL
FROM QUERY1 INNER JOIN QUERY2 ON _TIMESTAMP1 =_TIMESTAMP2-1
Related
I have start and end date columns, and there are some where the start date equals the end date of the previous row without a gap. I'm trying to get it so that it would basically go from the Start Date row who's End Date is null and kinda "zig-zag" up going until the Start Date does not match the End Date.
I've tried CTEs, and ROW_NUMBER() OVER().
START_DTE END_DTE
2018-01-17 2018-01-19
2018-01-26 2018-02-22
2018-02-22 2018-08-24
2018-08-24 2018-09-24
2018-09-24 NULL
Expected:
START_DTE END_DTE
2018-01-26 2018-09-24
EDIT
Using a proposed solution with an added CTE to ensure dates don't have times with them.
WITH
CTE_TABLE_NAME AS
(
SELECT
ID_NUM,
CONVERT(DATE,START_DTE) START_DTE,
CONVERT(DATE,END_DTE) END_DTE
FROM
TABLE_NAME
WHERE ID_NUM = 123
)
select min(start_dte) as start_dte, max(end_dte) as end_dte, grp
from (select t.*,
sum(case when prev_end_dte = end_dte then 0 else 1 end) over (order by start_dte) as grp
from (select t.*,
lag(end_dte) over (order by start_dte) as prev_end_dte
from CTE_TABLE_NAME t
) t
) t
group by grp;
The following query provides these results:
start_dte end_dte grp
2014-08-24 2014-12-19 1
2014-08-31 2014-09-02 2
2014-09-02 2014-09-18 3
2014-09-18 2014-11-03 4
2014-11-18 2014-12-09 5
2014-12-09 2015-01-16 6
2015-01-30 2015-02-02 7
2015-02-02 2015-05-15 8
2015-05-15 2015-07-08 9
2015-07-08 2015-07-09 10
2015-07-09 2015-08-25 11
2015-08-31 2015-09-01 12
2015-10-06 2015-10-29 13
2015-11-10 2015-12-11 14
2015-12-11 2015-12-15 15
2015-12-15 2016-01-20 16
2016-01-29 2016-02-01 17
2016-02-01 2016-03-03 18
2016-03-30 2016-08-29 19
2016-08-30 2016-12-06 20
2017-01-27 2017-02-20 21
2017-02-20 2017-08-15 22
2017-08-15 2017-08-29 23
2017-08-29 2018-01-17 24
2018-01-17 2018-01-19 25
2018-01-26 2018-02-22 26
2018-02-22 2018-08-24 27
2018-08-24 2018-09-24 28
2018-09-24 NULL 29
I tried using having count (*) > 1 as suggested, but it provided no results
Expected example
START_DTE END_DTE
2017-01-27 2018-01-17
2018-01-26 2018-09-24
You can identify where groups of connected rows start by looking for where adjacent rows are not connected. A cumulative sum of these starts then gives you the groups.
select min(start_dte) as start_dte, max(end_dte) as end_dte
from (select t.*,
sum(case when prev_end_dte = start_dte then 0 else 1 end) over (order by start_dte) as grp
from (select t.*,
lag(end_dte) over (order by start_dte) as prev_end_dte
from t
) t
) t
group by grp;
If you want only multiply connected rows (as implied by your question), then add having count(*) > 1 to the outer query.
Here is a db<>fiddle.
I am using an old SQL Server 2000.
Here is some sample data:
ROOMDATE rate bus_id quantity
2018-09-21 00:00:00.000 129 346686 2
2018-09-21 00:00:00.000 162 354247 36
2018-09-21 00:00:00.000 159 382897 150
2018-09-21 00:00:00.000 120 556111 25
2018-09-22 00:00:00.000 129 346686 8
2018-09-22 00:00:00.000 162 354247 86
2018-09-22 00:00:00.000 159 382897 150
2018-09-22 00:00:00.000 120 556111 25
2018-09-23 00:00:00.000 129 346686 23
2018-09-23 00:00:00.000 162 354247 146
2018-09-23 00:00:00.000 159 382897 9
2018-09-23 00:00:00.000 94 570135 23
Essentially what I am wanting is the MAX quantity of each day with it's corresponding rate and bus_id.
For example, I would want the following rows from my sample data above:
ROOMDATE rate bus_id quantity
2018-09-21 00:00:00.000 159 382897 150
2018-09-22 00:00:00.000 159 382897 150
2018-09-23 00:00:00.000 162 354247 146
From what I have read, SQL Server 2000 did not support ROW_NUMBER. But we can phrase your query using a subquery which finds the max quantity for each day:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT
CONVERT(char(10), ROOMDATE, 120) AS ROOMDATE,
MAX(quantity) AS max_quantity
FROM yourTable
GROUP BY CONVERT(char(10), ROOMDATE, 120)
) t2
ON CONVERT(char(10), t1.ROOMDATE, 120) = t2.ROOMDATE AND
t1.quantity = t2.max_quantity
ORDER BY
t1.ROOMDATE;
Demo
SQL Query not giving expected answer
SELECT CAST(PR.DateTimeStamp as date) AS PRDate,COUNT(PR.ID) AS PRCount
FROM tbl_Purchase PR
INNER JOIN tbl_PurchaseCategory PTC ON PR.ID = PTC.ID
WHERE PR.DateTimeStamp BETWEEN DATEADD(DAY,-30,'2017-12-07 09:00:00') AND
'2017-12-07 09:00:00' and PR.DepartmentID=1 and PTC.CategoryID=1 group by
CAST(PR.DateTimeStamp as date) order by CAST(PR.DateTimeStamp as date)
i want to select data like
PRDate PRCount
2017-12-07 3 // from 2017-12-08 09:00:00 to 2017-12-07 09:00:00
2017-12-06 31 // from 2017-12-07 09:00:00 to 2017-12-06 09:00:00
2017-12-05 10 // from 2017-12-06 09:00:00 to 2017-12-05 09:00:00
2017-12-04 23
2017-12-03 27
2017-12-02 15
2017-12-01 27
2017-11-30 39
2017-11-29 25
2017-11-28 27
2017-11-27 36
2017-11-26 30
2017-11-25 23
2017-11-24 18
2017-11-23 13
2017-11-22 16
2017-11-21 25
2017-11-20 15
2017-11-19 41
2017-11-18 11
2017-11-17 9
2017-11-16 19
2017-11-15 23
2017-11-14 17
2017-11-13 23
2017-11-12 20
2017-11-11 31
2017-11-10 29
2017-11-09 18
2017-11-08 29
2017-11-07 24
the above query is proving me data
12 to 12 time interval not from 9 to 9
You should subtract 9 hours from the date for the group by.
SELECT
CAST( DATEADD(HOUR,-9, PR.DateTimeStamp) as date) AS PRDate
, COUNT(PR.ID) AS PRCount
FROM tbl_Purchase PR
INNER JOIN tbl_PurchaseCategory PTC ON PR.ID = PTC.ID
WHERE
PR.DateTimeStamp BETWEEN DATEADD(DAY,-30,'2017-12-07 09:00:00') AND '2017-12-07 09:00:00'
AND PR.DepartmentID=1 and PTC.CategoryID=1
group by
CAST(DATEADD(HOUR,-9, PR.DateTimeStamp) as date)
order by
CAST(DATEADD(HOUR,-9, PR.DateTimeStamp) as date)
I need query, where I could group dates by every 7 days from beginning of the month. The problem is I have to exclude some days, specifically days before/after holidays and holidays. In my DateDay dimension there's a column, thats indicates which type of day it is. Example of calendar for November:
DTD_GID DTD_Date DTD_DayType
20161101 2016-11-01 2 --holiday was on 2016-10-31
20161102 2016-11-02 0
20161103 2016-11-03 0
20161104 2016-11-04 0
20161105 2016-11-05 0
20161106 2016-11-06 0
20161107 2016-11-07 0
20161108 2016-11-08 0
20161109 2016-11-09 0
20161110 2016-11-10 2
20161111 2016-11-11 1--public holiday
20161112 2016-11-12 2
20161113 2016-11-13 0
20161114 2016-11-14 0
20161115 2016-11-15 0
20161116 2016-11-16 0
20161117 2016-11-17 0
20161118 2016-11-18 0
20161119 2016-11-19 0
20161120 2016-11-20 0
20161121 2016-11-21 0
20161122 2016-11-22 0
20161123 2016-11-23 0
20161124 2016-11-24 0
20161125 2016-11-25 0
20161126 2016-11-26 0
20161127 2016-11-27 0
20161128 2016-11-28 0
20161129 2016-11-29 0
20161130 2016-11-30 0
I need to group it like that:
1: 2016-11-02 - 2016-11-08 (inclusive)
2: 2016-11-13 - 2016-11-19
3: 2016-11-20 - 2016-11-26
If such group would have less than 7 days, it shouldn't be returned by query.
Let me know if you need more details.
EDIT: I'm not sure if it will help, but I wrote query that's counting proper days in weeks
SELECT
DTD_DTMGID
,CONVERT(VARCHAR(5), DATEADD(WK, Week, 0), 103) + ' - ' + CONVERT(VARCHAR(5), DATEADD(DD, 6, DATEADD(WK, Week, 0)), 103) AS Week
,Cnt
FROM (
SELECT
DTD_DTMGID
, DATEDIFF(WK, 0, DTD_DATE) AS Week
, COUNT(*) AS Cnt
FROM DIM_DateDay
WHERE DTD_DayType = 0
GROUP BY DTD_DTMGID ,DATEDIFF(WK, 0, DTD_DATE)
) AS X
ORDER BY DTD_DTMGID
and result:
DTD_DTMGID Week Cnt
201301 31/12 - 06/01 2
201301 07/01 - 13/01 5
201301 14/01 - 20/01 7
201301 21/01 - 27/01 7
201301 28/01 - 03/02 5
201302 28/01 - 03/02 2
EDIT2: As output I expect ID's of days that are in those groups. As ID's I mean DTD_GID column which is primary key in my DateDay dimension.
So for group 1) I'd get following list:
20161102
20161103
20161104
20161105
20161106
20161107
20161108
Here is one solution that gives you start and end date of each 7-day range:
WITH CTE1 AS (
SELECT DTD_Date, DATEDIFF(DAY, ROW_NUMBER() OVER (ORDER BY DTD_Date), DTD_Date) AS Group1
FROM #Table1
WHERE DTD_DayType = 0
), CTE2 AS (
SELECT DTD_Date, Group1, (ROW_NUMBER() OVER (PARTITION BY Group1 ORDER BY Group1) - 1) / 7 AS Group2
FROM CTE1
)
SELECT MIN(DTD_Date) AS DTD_From, MAX(DTD_Date) AS DTD_Upto, COUNT(DTD_Date) AS C
FROM CTE2
GROUP BY Group1, Group2
ORDER BY DTD_From
-- HAVING COUNT(*) >= 7
Output:
DTD_From | DTD_Upto | C
-----------+------------+--
2016-11-02 | 2016-11-08 | 7
2016-11-09 | 2016-11-09 | 1
2016-11-13 | 2016-11-19 | 7
2016-11-20 | 2016-11-26 | 7
2016-11-27 | 2016-11-30 | 4
Here is how it works:
The first CTE removes holidays and assigns a group number to remaining rows. Consecutive dates get same group number (see this question).
The second CTE assigns another group number to each row in each group. Row number 1-7 get 0, 8-14 get 1, and so on.
Finally you group the results by the group numbers.
Sorry I am new to sql world could this statement be checkin time different with checkout time and remove checkinorout from the statement as you well see :
SELECT
USERINFO.Badgenumber AS USERID,
CHECKINOUT.CHECKTIME AS Checkin,
CHECKINOUT.CHECKTIME AS Checkout,
Machines.MachineAlias,
CHECKINOUT.checkinorout
FROM CHECKINOUT
INNER JOIN USERINFO ON CHECKINOUT.USERID = USERINFO.USERID
INNER JOIN Machines ON CHECKINOUT.SENSORID = Machines.MachineNumber
WHERE (CHECKINOUT.CHECKTIME > '2014-09-25 00:00:00.000')
order by checkin
Output:
USERID Checkin Checkout Machines checkinorout
32 2014-09-25 09:12:57.000 2014-09-25 09:12:57.000 HQ Checkin
32 2014-09-25 12:58:51.000 2014-09-25 12:58:51.000 HQ CheckOut
32 2014-09-26 18:03:33.000 2014-09-26 18:03:33.000 HQ Checkin
32 2014-09-26 22:03:11.000 2014-09-26 22:03:11.000 HQ CheckOut
32 2014-09-27 12:57:55.000 2014-09-27 12:57:55.000 HQ Checkin
32 2014-09-27 17:01:32.000 2014-09-27 17:01:32.000 HQ CheckOut
32 2014-09-28 13:05:03.000 2014-09-28 13:05:03.000 HQ Checkin
32 2014-09-28 17:35:29.000 2014-09-28 17:35:29.000 HQ CheckOut
32 2014-09-29 09:18:12.000 2014-09-29 09:18:12.000 HQ Checkin
32 2014-09-29 18:10:43.000 2014-09-29 18:10:43.000 HQ CheckOut
32 2014-09-30 09:12:13.000 2014-09-30 09:12:13.000 HQ Checkin
I need the output be like this
USERID Checkin Checkout Machines
32 2014-09-25 09:12:57.000 2014-09-25 12:58:51.000 HQ
32 2014-09-26 18:03:33.000 2014-09-26 22:03:11.000 HQ
32 2014-09-27 12:57:55.000 2014-09-27 17:01:32.000 HQ
32 2014-09-28 13:05:03.000 2014-09-28 17:35:29.000 HQ
32 2014-09-29 09:18:12.000 2014-09-29 18:10:43.000 HQ
Thanks MR #sgeddes but when i edit your statement to have a result
with cte as (
select *,
row_number() over (partition by userid, checkinorout order by CHECKTIME) rn
from CHECKINOUT
)
select userid,
max(case when checkinorout = 'checkin' then CHECKTIME end) checkin,
max(case when checkinorout = 'checkout' then CHECKTIME end) checkout
from cte where USERID=15 and CHECKTIME between '2014-9-21 00:00:00.000' and '2014-10-25 00:00:00.000'
group by userid , rn
userid checkin checkout
15 NULL 2014-09-21 18:50:24.000
15 NULL 2014-09-22 18:06:15.000
15 NULL 2014-09-23 18:01:30.000
15 NULL 2014-09-24 16:52:36.000
15 NULL 2014-09-25 12:58:51.000
15 NULL 2014-09-26 22:03:11.000
15 NULL 2014-09-27 17:01:32.000
15 NULL 2014-09-28 17:35:29.000
15 NULL 2014-09-29 18:10:43.000
15 NULL 2014-09-30 18:11:19.000
15 NULL 2014-10-01 17:52:49.000
15 NULL 2014-10-12 20:13:10.000
15 2014-09-21 10:17:24.000 2014-10-13 22:13:11.000
15 2014-09-22 09:18:29.000 2014-10-14 21:49:28.000
15 2014-09-23 09:10:15.000 2014-10-15 10:14:09.000
15 2014-09-24 09:43:27.000 2014-10-16 17:55:06.000
15 2014-09-25 09:12:57.000 2014-10-17 23:17:00.000
15 2014-09-26 18:03:33.000 2014-10-20 12:38:22.000
15 2014-09-27 12:57:55.000 2014-10-21 07:31:39.000
15 2014-09-28 13:05:03.000 2014-10-22 05:51:47.000
15 2014-09-29 09:18:12.000 2014-10-24 11:26:06.000
15 2014-09-30 09:12:13.000 NULL
15 2014-10-01 10:16:59.000 NULL
15 2014-10-02 10:13:52.000 NULL
15 2014-10-03 00:59:18.000 NULL
15 2014-10-11 22:07:06.000 NULL
15 2014-10-12 09:58:34.000 NULL
15 2014-10-13 05:09:34.000 NULL
15 2014-10-14 11:42:58.000 NULL
15 2014-10-15 04:48:27.000 NULL
15 2014-10-15 15:49:06.000 NULL
15 2014-10-16 09:14:21.000 NULL
15 2014-10-16 21:14:18.000 NULL
15 2014-10-17 00:59:57.000 NULL
15 2014-10-18 17:42:26.000 NULL
15 2014-10-20 01:22:01.000 NULL
15 2014-10-21 01:24:30.000 NULL
15 2014-10-22 00:10:34.000 NULL
15 2014-10-23 20:01:02.000 NULL
15 2014-10-24 01:08:51.000 NULL
and i need it to be
userid checkin checkout
15 2014-09-21 10:17:24.000 2014-09-21 18:50:24.000
15 2014-09-22 09:18:29.000 2014-09-22 18:06:15.000
15 2014-09-23 09:10:15.000 2014-09-23 18:01:30.000
15 2014-09-24 09:43:27.000 2014-09-24 16:52:36.000
15 2014-09-25 09:12:57.000 2014-09-25 12:58:51.000
15 2014-09-26 18:03:33.000 2014-09-26 22:03:11.000
15 2014-09-27 12:57:55.000 2014-09-27 17:01:32.000
Thanks Mr #slavoo
what i have when i try ....
SELECT
u.Badgenumber AS USERID,
c.CHECKTIME AS Checkout,
checkingOut.time AS Checkin,
m.MachineAlias
FROM CHECKINOUT c
INNER JOIN USERINFO u ON c.USERID = u.USERID
INNER JOIN Machines m ON c.SENSORID = m.MachineNumber
OUTER APPLY
(
SELECT top 1 c2.CHECKTIME as time FROM CHECKINOUT c2
WHERE c2.checkinorout = 'Checkout'
AND c.USERID = c2.USERID
AND c.SENSORID = c2.SENSORID
AND c.CHECKTIME < c2.CHECKTIME
order by c2.CHECKTIME asc
) as checkingOut
WHERE (c.CHECKTIME between '2014-10-19 00:00:00.000' and '2014-10-27 00:00:00.000' )
and u.Badgenumber=660
AND c.checkinorout = 'Checkin'
AND checkingOut.time is not null
order by checkingOut.time
The output:
USERID Checkout Checkin MachineAlias
660 2014-10-19 01:56:47.000 2014-10-19 17:27:41.000 Branch4
660 2014-10-20 02:00:14.000 2014-10-20 17:39:35.000 Branch4
660 2014-10-21 01:55:49.000 2014-10-21 16:57:22.000 Branch4
660 2014-10-22 01:59:23.000 2014-10-25 16:48:29.000 Branch4
660 2014-10-23 16:59:34.000 2014-10-25 16:48:29.000 Branch4
660 2014-10-24 16:58:36.000 2014-10-25 16:48:29.000 Branch4
660 2014-10-25 01:56:47.000 2014-10-25 16:48:29.000 Branch4
and i need it to be
USERID Checkout Checkin MachineAlias
660 2014-10-20 02:00:14.000 2014-10-19 17:27:41.000 Branch4
660 2014-10-21 01:55:49.000 2014-10-20 17:39:35.000 Branch4
660 2014-10-22 01:59:23.000 2014-10-21 16:57:22.000 Branch4
660 Null 2014-10-23 16:59:34.000 Branch4
660 2014-10-25 01:56:47.000 2014-10-24 16:58:36.000 Branch4
660 2014-10-26 00:55:35.000 2014-10-25 16:48:29.000 Branch4
and this is the table i read from it
select USERID ,CHECKTIME,checkinorout from CHECKINOUT where USERID=80 and CHECKTIME between '2014-10-19 00:00:00.000' and '2014-10-27 00:00:00.000'
order by CHECKTIME
and this is the full transaction for this user
80 2014-10-19 01:56:47.000 Checkin
80 2014-10-19 17:27:41.000 CheckOut
80 2014-10-20 02:00:14.000 Checkin
80 2014-10-20 17:39:35.000 CheckOut
80 2014-10-21 01:55:49.000 Checkin
80 2014-10-21 16:57:22.000 CheckOut
80 2014-10-22 01:59:23.000 Checkin
80 2014-10-23 16:59:34.000 Checkin
80 2014-10-24 16:58:36.000 Checkin
80 2014-10-25 01:56:47.000 Checkin
80 2014-10-25 16:48:29.000 CheckOut
80 2014-10-26 00:55:35.000 Checkin
for your note i have script its update the check in or out in checkinorout column
to know this report be finger print check in and check out report
and if he found no check in leave it Null and if he found the check out null leave it null ( this employ have shift check in 5:00:00 pm and check out 2:00:00 am ) ; .
SELECT
u.Badgenumber AS USERID,
c.CHECKTIME AS Checkin,
checkingOut.time AS Checkout,
m.MachineAlias
FROM CHECKINOUT c
INNER JOIN users u ON c.USERID = u.USERID
INNER JOIN Machines m ON c.SENSORID = m.MachineNumber
OUTER APPLY
(
SELECT top 1 c2.CHECKTIME as time FROM CHECKINOUT c2
WHERE c2.checkinorout = 'Checkout'
AND c.USERID = c2.USERID
AND c.SENSORID = c2.SENSORID
AND c.CHECKTIME < c2.CHECKTIME
AND CAST(c.CHECKTIME as DATE) = CAST(c2.CHECKTIME as DATE)
order by c2.CHECKTIME asc
) as checkingOut
WHERE (c.CHECKTIME > '2014-09-25 00:00:00.000')
AND c.checkinorout = 'Checkin'
order by checkin
SQL Fiddle
SQL Fiddle after update
Or this:
SELECT
u.Badgenumber AS USERID,
c.CHECKTIME AS Checkin,
checkingOut.time AS Checkout,
Machines.MachineAlias
FROM CHECKINOUT c
INNER JOIN users u ON c.USERID = u.USERID
INNER JOIN Machines ON c.SENSORID = Machines.MachineNumber
OUTER APPLY
(
SELECT top 1 c2.CHECKTIME as time FROM CHECKINOUT c2
WHERE c2.checkinorout = 'Checkout'
AND c.USERID = c2.USERID
AND c.SENSORID = c2.SENSORID
AND c.CHECKTIME < c2.CHECKTIME
AND NOT EXISTS (SELECT * FROM CHECKINOUT c3
WHERE c3.checkinorout = 'Checkin'
AND c3.USERID = c2.USERID
AND c3.SENSORID = c2.SENSORID
AND c3.CHECKTIME > c.CHECKTIME
AND c3.CHECKTIME < c2.CHECKTIME)
order by c2.CHECKTIME asc
) as checkingOut
WHERE (c.CHECKTIME > '2014-09-25 00:00:00.000')
AND c.checkinorout = 'Checkin'
order by checkin
SqlFiddle
You can use ROW_NUMBER() to establish a grouping between your checkins and checkouts. Then you need to pivot your results -- you can use MAX with CASE to do that:
Here's a simplified version using a common table expression:
with cte as (
select *,
row_number() over (partition by userid, checkinorout order by checkin) rn
from results
)
select userid,
max(case when checkinorout = 'checkin' then checkin end) checkin,
max(case when checkinorout = 'checkout' then checkout end) checkout,
machines
from cte
group by userid, machines, rn
SQL Fiddle Demo
Edit, given your comments, can you not just use a HAVING clause to remove the NULL records?
having max(case when checkinorout = 'checkin' then checkin end) is not null
and max(case when checkinorout = 'checkout' then checkout end) is not null
Updated Fiddle