针对给定用例建议 SQL 查询

Suggest SQL query for given use case

原文Table

Id | Time | Status
------------------
1  |  5   |  T
1  |  6   |  F
2  |  3   |  F
1  |  2   |  F
2  |  4   |  T
3  |  7   |  F
2  |  3   |  T
3  |  1   |  F
4  |  7   |  H
4  |  6   |  S
4  |  5   |  F
4  |  4   |  T
5  |  5   |  S
5  |  6   |  F

预计Table

Id | Time | Status
------------------
1  |  6   |  F
3  |  7   |  F 
4  |  5   |  F 

我想要所有状态为 F 但时间应该最长的不同 ID,如果对于给定的最长时间,任何 ID 状态为 T,则不应选择该 ID。此外,只有那些至少有一个 T 的 ID 才应该被选中。例如,4 不会被选中,因为它没有任何 'T' 作为状态。

请帮助编写 SQL 查询。

试试下面的方法-

select * from tablename t 
where time = (select max(time) from tablename t1 where t.id=t1.id and Status='F')
and Status='F'

以下应该有效

select id,max(time) as time,status
  from table
where status='F'
group by id,status
select id, max(time), status
from stuff s
where status = 'F'
and id not in (
    select id 
    from stuff s2
    where s2.id = s.id
    and s2.time > s.time
    and s2.status = 'T')
 group by id, status;

你可以看到 Fiddle here.

据我了解,您想找到状态为F的每个ID(max(time))的最高时间,但前提是没有以后的记录状态为[=17] =].子查询过滤掉存在状态为 T 的较晚记录的记录。

WITH MAX_TIME_ID AS (
    SELECT
          ID
          ,MAX(TIME) AS MAX_TIME
    GROUP BY
          ID
)
SELECT
       O.*
FROM 
     ORIGINAL_TABLE O
INNER JOIN
     MAX_TIME_ID MAX
ON
    O.ID = MAX.ID
WHERE
    O.STATUS = 'F'

CTE 将找到每个 ID 的最长时间,只有当最新的是 'F'.

时,使用状态上的 where 子句的内部连接才会 select 它

您可以在 WHERE 子句中使用 EXISTSNOT EXISTS

select t.*
from tablename t
where t.status = 'F'
and exists (select 1 from tablename where id = t.id and status = 'T')
and not exists (
    select 1 
    from tablename
    where id = t.id and status in ('F', 'T') and time > t.time
)

参见demo
结果:

| Id  | Time | Status |
| --- | ---- | ------ |
| 1   | 6    | F      |
| 4   | 5    | F      |

我只会使用 window 函数:

select t.*
from (select t.*
             row_number() over (partition by id order by time desc) as seqnum,
             sum(case when status = 'T' then 1 else 0 end) over (partition by id) as num_t
      from t
     ) t
where num_t > 0 and
      seqnum = 1 and status = 'F';

还有另一种有趣的方法可以通过聚合来做到这一点:

select id, max(time) as time, 'F' as status
from t
group by id
having sum(case when status = 'T' then 1 else 0 end) > 0 and
       max(time) = max(case when status 'F' then time end);