考虑下表:
id | date | status
1 | 2014-01-10 | 1
1 | 2014-02-10 | 1
1 | 2014-03-10 | 1
1 | 2014-04-10 | 1
1 | 2014-05-10 | 0
1 | 2014-06-10 | 0
------------------------
2 | 2014-01-10 | 1
2 | 2014-02-10 | 1
2 | 2014-03-10 | 0
2 | 2014-04-10 | 1
2 | 2014-05-10 | 0
2 | 2014-06-10 | 0
------------------------
3 | 2014-01-10 | 1
3 | 2014-02-10 | 0
3 | 2014-03-10 | 0
3 | 2014-04-10 | 1
3 | 2014-05-10 | 0
3 | 2014-06-10 | 0
------------------------
4 | 2014-01-10 | 0
4 | 2014-02-10 | 1
4 | 2014-03-10 | 1
4 | 2014-04-10 | 1
4 | 2014-05-10 | 0
4 | 2014-06-10 | 0
------------------------
5 | 2014-01-10 | 0
5 | 2014-02-10 | 1
5 | 2014-03-10 | 0
5 | 2014-04-10 | 1
5 | 2014-05-10 | 0
5 | 2014-06-10 | 0
------------------------
Id字段是用户ID,日期字段是某个检查点到期时的状态,状态指示检查点是否由其用户完成。
我在尝试检测跳过某些检查点的用户时遇到了很大的麻烦,比如有ids 2,3,4和5的用户。实际上我需要一个查询,列出中间缺少检查点的ID系列的开头,只返回ID。
我已经努力找到一种方法,只是查询,但我无法创建一个。我知道我可以编写一些脚本,但我正在处理的项目要求我只使用SQL。
任何人对如何实现这一点有任何想法?
编辑:根据mods的建议,这里有更多细节和一些我尝试失败的事情:
我最成功的尝试是计算使用此查询为每个ID注册了多少个状态:
SELECT
id,
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS check,
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS non_check
FROM
example_table
GROUP BY
id
ORDER BY
id
获得以下结果:
id | check | non_check
1 | 4 | 2
2 | 3 | 3
3 | 2 | 4
4 | 3 | 3
5 | 2 | 4
通过该结果,我可以选择每个id条目,通过它在状态字段上执行SUM的检查结果进行限制,如果SUM结果与检查结果相等,则检查点是连续的,如:
WITH tbl AS (
SELECT id, status, SUM(status) AS "sum"
FROM (
SELECT id, status FROM example_table WHERE id = 1 ORDER BY date LIMIT 4
) AS tbl2
GROUP BY
status,id
)
SELECT
id,"sum"
FROM
tbl
WHERE
status = 1
获得以下结果:
id | sum
1 | 4
由于总和结果等于检查第一个查询,我可以确定检查点是连续的。但这次以id 2为例,它的查询是:
WITH tbl AS (
SELECT id, status, SUM(status) AS "sum"
FROM (
SELECT id, status FROM example_table WHERE id = 2 ORDER BY date LIMIT 3
) AS tbl2
GROUP BY
status,id
)
SELECT
id,"sum"
FROM
tbl
WHERE
status = 1
请注意,我根据我正在使用的ID及其在第一个查询中的检查结果更改了WHERE上的id和LIMIT值,并得到以下结果:
id | sum
2 | 2
由于该查询中id 2的sum字段值与其检查值不同,我可以说它不是连续的。每个id都可以重复这种模式。
正如我之前所说,要以这种方式解决问题,我需要通过代码来完成,但在特定情况下,我需要它在SQL中。
我还发现了以下文章:
postgres detect repeating patterns of zeros
问题类似于我的问题,但他想检测重复的零,它有点启发我,但还不足以解决我自己的问题。
提前致谢!
答案 0 :(得分:1)
您正在寻找的模式是错过的检查点,然后是完成的检查点。使用下一个(按时间戳)检查点加入用户的每个检查点,然后查找状态0加入状态1。
以下是一个例子:
create table tab (id int,date date,status int);
insert into tab values(1 , '2014-01-10' , 1),(1 , '2014-02-10' , 1),(1 , '2014-03-10' , 1),(1 , '2014-04-10' , 1),(1 , '2014-05-10' , 0),(1 , '2014-06-10' , 0),(2 , '2014-01-10' , 1),(2 , '2014-02-10' , 1),(2 , '2014-03-10' , 0),(2 , '2014-04-10' , 1),(2 , '2014-05-10' , 0),(2 , '2014-06-10' , 0),(3 , '2014-01-10' , 1),(3 , '2014-02-10' , 0),(3 , '2014-03-10' , 0),(3 , '2014-04-10' , 1),(3 , '2014-05-10' , 0),(3 , '2014-06-10' , 0),(4 , '2014-01-10' , 0),(4 , '2014-02-10' , 1),(4 , '2014-03-10' , 1),(4 , '2014-04-10' , 1),(4 , '2014-05-10' , 0),(4 , '2014-06-10' , 0),(5 , '2014-01-10' , 0),(5 , '2014-02-10' , 1),(5 , '2014-03-10' , 0),(5 , '2014-04-10' , 1),(5 , '2014-05-10' , 0),(5 , '2014-06-10' , 0);
with tabwithrow as
(select *
, row_number() OVER(PARTITION by id order by date) rnum
from tab)
select *
from tabwithrow a
join tabwithrow b on b.rnum = a.rnum + 1
and a.id = b.id
and a.status = 0
and b.status = 1;