简体   繁体   中英

Sql query to only select rows if last entry of item meets condition

I'm looking for the following query in SQL - ie select ID from table where entry is within 'last hour' and the last check-in value was 'false'.

Sample Data 'Table1':

ID(int), Check-In(boolean), Name(nvarchar), Entry(DateTime)*, PersonID(int)
*DateTime Format: DD/MM/YYYY HH:MM:SS

1, true, Klaus, 14/05/2015 15:45:21, 100
2, true, Klaus, 14/05/2015 16:05:22, 100
3, false, Klaus, 14/05/2015 16:06:04, 100
4, true, Pete, 14/05/2015 16:20:33, 101
5, false, Michelle, 14/05/2015 16:24:22, 105
6, true, Pete, 14/05/2015 16:25:55, 101
7, false, Pete, 14/05/2015 16:28:44, 101
8, true, Pete, 14/05/2015 16:29:36, 101

Result of Query:

Select ID from Table1 where time = last_hour and (LAST) Check-In was false'

= 3 and 5 (do not select 7)

In the above example, I don't want to select ID 7 as the last check-in of Pete was true (ID 8).

Any ideas how I can achieve that with a SQL query? Is this possible with a simple query?

To make sure the last checkin is false , you must check that there is not a newer row in the table.

You can do that with a "not exists" clause.

Try this one:

    select * from table1 t1
    where entry > DATE_SUB(NOW(), INTERVAL 1 HOUR)
    and checkin = false
    and not exists (
      select * from table1 t2
      where t2.name = t1.name
      and t2.entry > t1.entry)

This is other way using partition . I can't run the explain now. But my guess is this version have to do less scans than a exists for each row.

SQL Fiddle Demo

Take note fiddle doesn't have the 1 hour validation
Also sql server bit field is (0,1) not (false, true)

  • row = 1 : Select the last entry for each user
  • CheckIn = 0 is the CheckIn = False

.

 WITH last_entry as (
     SELECT *, ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Entry DESC) AS row
     FROM table1
     WHERE entry > DATE_SUB(NOW(), INTERVAL 1 HOUR)
 )
 SELECT *
 FROM last_entry
 WHERE 
     row = 1
 and CheckIn = 0

Using LEAD if you are using SQL Server 2012+ to determine if it was last false attempt.

Demo SqlFiddle

CREATE TABLE tab(
    Id       INT 
   ,Check_in BIT    /* BIT 0 - false, 1 - true) */
   ,Name     NVARCHAR(10)
   ,Entry    DATETIME
   ,PersonId INT)

SET DATEFORMAT dmy;

INSERT INTO tab(Id, Check_in, Name, Entry, PersonId)
SELECT 1, 1, 'Klaus', '14/05/2015 15:45:21',  100  UNION ALL
SELECT 2, 1, 'Klaus', '14/05/2015 16:05:22',  100  UNION ALL
SELECT 3, 0, 'Klaus', '14/05/2015 16:06:04',  100  UNION ALL
SELECT 4, 1, 'Pete',  '14/05/2015 16:20:33',  101  UNION ALL
SELECT 5, 0, 'Michelle', '14/05/2015 16:24:22',105 UNION ALL
SELECT 6, 1, 'Pete', '14/05/2015 16:25:55', 101    UNION ALL
SELECT 7, 0, 'Pete', '14/05/2015 16:28:44', 101    UNION ALL
SELECT 8, 1, 'Pete', '14/05/2015 16:29:36', 101

WITH cte(Id, Next_id, Entry, Name, Check_in, PersonId) 
AS 
(
    SELECT 
        Id
       ,LEAD(id, 1, NULL) OVER ( PARTITION BY Name ORDER BY Entry )
       ,Entry
       ,Name
       ,Check_in
       ,PersonId
    FROM tab
    WHERE DATEDIFF(minute, Entry, GETDATE()) < 60
)
SELECT Id, Entry, Name, Check_in, PersonId
FROM cte
WHERE check_in = 0
      AND [Next_id] IS NULL;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM