Sql查询仅在项的最后一个条目满足条件时选择行

时间:2015-08-23 21:40:32

标签: sql sql-server

我在SQL中寻找以下查询 - 即从表格中选择ID,其中条目在“最后一小时”内,最后签到值为“false”。

样本数据'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

查询结果:

从Table1中选择ID,其中time = last_hour和(LAST)Check-In为false'

= 3和5(不要选择7)

在上面的例子中,我不想选择ID 7,因为Pete的最后一次登记是真的(ID 8)。

我是如何通过SQL查询实现这一目标的?这可以通过简单的查询来实现吗?

3 个答案:

答案 0 :(得分:3)

要确保最后签入为false,您必须检查表格中是否有较新的行。

你可以用“不存在”条款来做到这一点。

试试这个:

    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)

答案 1 :(得分:2)

这是使用partition的另一种方式。我现在无法解释。但我的猜测是这个版本的扫描次数要少于每行exists

SQL Fiddle Demo

  

注意小提琴没有1小时的验证
  sql server位字段也是(0,1)不是(false,true)

  • row = 1:选择每个用户的最后一个条目
  • CheckIn = 0是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

答案 2 :(得分:1)

如果您使用SQL Server 2012+来确定它是否是上次错误尝试,请使用LEAD

<强> 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;