楼主: 胡作飛为

[SQL] 计算连续签到天数

[复制链接]
论坛徽章:
5
摩羯座
日期:2016-01-14 14:06:40双鱼座
日期:2016-01-18 14:59:42天枰座
日期:2016-01-18 16:43:02秀才
日期:2016-02-18 10:08:1419周年集字徽章-周
日期:2022-01-21 13:37:36
11#
 楼主| 发表于 2022-1-25 10:03 | 只看该作者
newkid 发表于 2022-1-23 21:32
最后的partition by有个bug, 修改一下:with t as (    select '2022-01-01' as dt, 0 as sign_in from dua ...

还是得看大佬呀

使用道具 举报

回复
论坛徽章:
0
12#
发表于 2022-1-29 18:44 | 只看该作者
with t as (
        select '2022-01-01' as dt, 1 as sign_in from dual union
        select '2022-01-02' as dt, 1 as sign_in from dual union
        select '2022-01-03' as dt, 1 as sign_in from dual union
        select '2022-01-04' as dt, 0 as sign_in from dual union
        select '2022-01-05' as dt, 1 as sign_in from dual union
        select '2022-01-06' as dt, 0 as sign_in from dual union
        select '2022-01-07' as dt, 1 as sign_in from dual union
        select '2022-01-08' as dt, 1 as sign_in from dual union
        select '2022-01-09' as dt, 1 as sign_in from dual union
        select '2022-01-10' as dt, 1 as sign_in from dual union
        select '2022-01-11' as dt, 1 as sign_in from dual union
        select '2022-01-12' as dt, 1 as sign_in from dual union
        select '2022-01-13' as dt, 0 as sign_in from dual union
        select '2022-01-14' as dt, 0 as sign_in from dual union
        select '2022-01-15' as dt, 1 as sign_in from dual union
        select '2022-01-16' as dt, 1 as sign_in from dual union
        select '2022-01-17' as dt, 1 as sign_in from dual union
        select '2022-01-18' as dt, 1 as sign_in from dual
    ),
    s as (select t.dt,t.sign_in,to_date(t.dt,'YYYY-MM-DD') - row_number() over (order by dt) as grp from t where sign_in=1),
    r as (select * from s union select dt,sign_in,to_date('1900-01-01','YYYY-MM-DD') as grp from t where sign_in=0)
    select dt,sign_in,decode(grp,to_date('1900-01-01','YYYY-MM-DD'),0,row_number() over (partition by grp order by dt)) as 连续签到 from r order by 1;

使用道具 举报

回复
论坛徽章:
0
13#
发表于 2022-1-29 21:09 | 只看该作者
with t as (
        select '2022-01-01' as dt, 1 as sign_in from dual union
        select '2022-01-02' as dt, 1 as sign_in from dual union
        select '2022-01-03' as dt, 1 as sign_in from dual union
        select '2022-01-04' as dt, 0 as sign_in from dual union
        select '2022-01-05' as dt, 1 as sign_in from dual union
        select '2022-01-06' as dt, 0 as sign_in from dual union
        select '2022-01-07' as dt, 1 as sign_in from dual union
        select '2022-01-08' as dt, 1 as sign_in from dual union
        select '2022-01-09' as dt, 1 as sign_in from dual union
        select '2022-01-10' as dt, 1 as sign_in from dual union
        select '2022-01-11' as dt, 1 as sign_in from dual union
        select '2022-01-12' as dt, 1 as sign_in from dual union
        select '2022-01-13' as dt, 0 as sign_in from dual union
        select '2022-01-14' as dt, 0 as sign_in from dual union
        select '2022-01-15' as dt, 1 as sign_in from dual union
        select '2022-01-16' as dt, 1 as sign_in from dual union
        select '2022-01-17' as dt, 1 as sign_in from dual union
        select '2022-01-18' as dt, 1 as sign_in from dual
    ),
    s as (select t.dt,t.sign_in,to_date(t.dt,'YYYY-MM-DD') - sysdate - row_number() over (order by dt) as grp from t where sign_in=1),
    r as (select * from s union select dt,sign_in,0 as grp from t where sign_in=0)
    select dt,sign_in,decode(grp,0,0,row_number() over (partition by grp order by dt)) as 连续签到 from r order by 1;

使用道具 举报

回复
论坛徽章:
0
14#
发表于 2022-2-2 14:52 | 只看该作者
newkid 发表于 2022-1-23 09:28
如果是12C 以上,with t as (    select '2022-01-01' as dt, 1 as sign_in from dual union    select '20 ...

和目标貌似有点区别,我小改了一下
  1. with t as (
  2.     select '2022-01-01' as dt, 1 as sign_in from dual union
  3.     select '2022-01-02' as dt, 1 as sign_in from dual union
  4.     select '2022-01-03' as dt, 1 as sign_in from dual union
  5.     select '2022-01-04' as dt, 0 as sign_in from dual union
  6.     select '2022-01-05' as dt, 1 as sign_in from dual union
  7.     select '2022-01-06' as dt, 0 as sign_in from dual union
  8.     select '2022-01-07' as dt, 1 as sign_in from dual union
  9.     select '2022-01-08' as dt, 1 as sign_in from dual union
  10.     select '2022-01-09' as dt, 1 as sign_in from dual union
  11.     select '2022-01-10' as dt, 1 as sign_in from dual union
  12.     select '2022-01-11' as dt, 1 as sign_in from dual union
  13.     select '2022-01-12' as dt, 1 as sign_in from dual union
  14.     select '2022-01-13' as dt, 0 as sign_in from dual union
  15.     select '2022-01-14' as dt, 0 as sign_in from dual union
  16.     select '2022-01-15' as dt, 1 as sign_in from dual union
  17.     select '2022-01-16' as dt, 1 as sign_in from dual union
  18.     select '2022-01-17' as dt, 1 as sign_in from dual union
  19.     select '2022-01-18' as dt, 1 as sign_in from dual
  20. )
  21. select dt,sign_in,cnt from t
  22. match_recognize(
  23.   -- partition by person_id
  24.   order by dt
  25.   measures  count(decode(sign_in,0,null,1)) cnt
  26.   ALL ROWS PER MATCH
  27.   pattern(a* b)
  28.   define a as sign_in = next(sign_in)
  29. );
复制代码

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
15#
发表于 2022-2-2 22:25 | 只看该作者
wwwwwwgame 发表于 2022-2-2 14:52
和目标貌似有点区别,我小改了一下

谢谢参与,送上我以前翻译的文档:
http://www.itpub.net/forum.php?m ... ;extra=#pid23315171

使用道具 举报

回复
论坛徽章:
0
16#
发表于 2022-2-3 21:40 来自手机 | 只看该作者
Let’s simulate match clause in procedural way.  With t0 as ..., t1 as ... order by dt, tmp(rn, ...) as (select 1 rn, signin*1 cnt ... from t1 where rn=1 union all select tmp.rn+1, decode(t1.signin, tmp.signin, tmp.cnt+Signin*1, signin+1), ... from tmp,t1 where t1.rn =tmp.rn+1) select * from tmp.

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
17#
发表于 2022-2-3 22:11 | 只看该作者
jihuyao 发表于 2022-2-3 21:40
Let’s simulate match clause in procedural way.  With t0 as ..., t1 as ... order by dt, tmp(rn, ...) ...

你是先排序,然后用递归WITH子查询逐行拼到结果里面去。当然这样是可以,但效率很低,每行都要做一个JOIN。用MODEL也可以做类似的事情,效率也是很低。
MATCH_RECOGNIZE 在这方面是无敌的。

使用道具 举报

回复
论坛徽章:
0
18#
发表于 2022-8-24 14:43 | 只看该作者
with  t as(
    select '2022-01-01' as dt, 1 as sign_in from dual union
    select '2022-01-02' as dt, 1 as sign_in from dual union
    select '2022-01-03' as dt, 1 as sign_in from dual union
    select '2022-01-04' as dt, 0 as sign_in from dual union
    select '2022-01-05' as dt, 1 as sign_in from dual union
    select '2022-01-06' as dt, 0 as sign_in from dual union
    select '2022-01-07' as dt, 1 as sign_in from dual union
    select '2022-01-08' as dt, 1 as sign_in from dual union
    select '2022-01-09' as dt, 1 as sign_in from dual union
    select '2022-01-10' as dt, 1 as sign_in from dual union
    select '2022-01-11' as dt, 1 as sign_in from dual union
    select '2022-01-12' as dt, 1 as sign_in from dual union
    select '2022-01-13' as dt, 0 as sign_in from dual union
    select '2022-01-14' as dt, 0 as sign_in from dual union
    select '2022-01-15' as dt, 1 as sign_in from dual union
    select '2022-01-16' as dt, 1 as sign_in from dual union
    select '2022-01-17' as dt, 1 as sign_in from dual union
    select '2022-01-18' as dt, 1 as sign_in from dual
)
select dt,sign_in ,case  when rn>0 then rn else 0 end "连续签到"
from t left join (
select dt,r,datesub,row_number()over(partition by datesub order by dt) rn
from (
select dt,r,to_date(dt,'yyyy-mm-dd')-r as datesub -----date_add 只有sql中有
from (
    select dt,dense_rank()over(order by dt) r
    from t
    where sign_in=1
) temp ) t2) t3 using(dt)
order by dt;

使用道具 举报

回复
论坛徽章:
18
优秀写手
日期:2014-02-27 06:00:13秀才
日期:2017-12-12 09:52:44秀才
日期:2017-08-11 15:37:32弗兰奇
日期:2017-07-04 09:16:01秀才
日期:2017-06-29 10:16:48乌索普
日期:2017-05-26 08:58:24娜美
日期:2017-05-18 16:07:23ITPUB15周年纪念
日期:2017-05-02 15:22:36妮可·罗宾
日期:2017-04-06 10:06:19处女座
日期:2016-03-10 09:03:26
19#
发表于 2022-8-29 09:48 | 只看该作者

model:
with t as (
    select '2022-01-01' as dt, 1 as sign_in from dual union
    select '2022-01-02' as dt, 1 as sign_in from dual union
    select '2022-01-03' as dt, 1 as sign_in from dual union
    select '2022-01-04' as dt, 0 as sign_in from dual union
    select '2022-01-05' as dt, 1 as sign_in from dual union
    select '2022-01-06' as dt, 0 as sign_in from dual union
    select '2022-01-07' as dt, 1 as sign_in from dual union
    select '2022-01-08' as dt, 1 as sign_in from dual union
    select '2022-01-09' as dt, 1 as sign_in from dual union
    select '2022-01-10' as dt, 1 as sign_in from dual union
    select '2022-01-11' as dt, 1 as sign_in from dual union
    select '2022-01-12' as dt, 1 as sign_in from dual union
    select '2022-01-13' as dt, 0 as sign_in from dual union
    select '2022-01-14' as dt, 0 as sign_in from dual union
    select '2022-01-15' as dt, 1 as sign_in from dual union
    select '2022-01-16' as dt, 1 as sign_in from dual union
    select '2022-01-17' as dt, 1 as sign_in from dual union
    select '2022-01-18' as dt, 1 as sign_in from dual
)
select  dt as "日期",sign_in as "签到",lxqd as "连续签到" from t
model
dimension by (row_number()over(order by dt) as rn)
measures(dt,0 as lxqd,sign_in)
rules
(
lxqd[any]= case when sign_in[cv()]=0 then 0 else nvl(lxqd[cv()-1],0)+1 end
)

使用道具 举报

回复
论坛徽章:
18
优秀写手
日期:2014-02-27 06:00:13秀才
日期:2017-12-12 09:52:44秀才
日期:2017-08-11 15:37:32弗兰奇
日期:2017-07-04 09:16:01秀才
日期:2017-06-29 10:16:48乌索普
日期:2017-05-26 08:58:24娜美
日期:2017-05-18 16:07:23ITPUB15周年纪念
日期:2017-05-02 15:22:36妮可·罗宾
日期:2017-04-06 10:06:19处女座
日期:2016-03-10 09:03:26
20#
发表于 2022-8-29 09:57 | 只看该作者
递归
with t as (
    select '2022-01-01' as dt, 1 as sign_in from dual union
    select '2022-01-02' as dt, 1 as sign_in from dual union
    select '2022-01-03' as dt, 1 as sign_in from dual union
    select '2022-01-04' as dt, 0 as sign_in from dual union
    select '2022-01-05' as dt, 1 as sign_in from dual union
    select '2022-01-06' as dt, 0 as sign_in from dual union
    select '2022-01-07' as dt, 1 as sign_in from dual union
    select '2022-01-08' as dt, 1 as sign_in from dual union
    select '2022-01-09' as dt, 1 as sign_in from dual union
    select '2022-01-10' as dt, 1 as sign_in from dual union
    select '2022-01-11' as dt, 1 as sign_in from dual union
    select '2022-01-12' as dt, 1 as sign_in from dual union
    select '2022-01-13' as dt, 0 as sign_in from dual union
    select '2022-01-14' as dt, 0 as sign_in from dual union
    select '2022-01-15' as dt, 1 as sign_in from dual union
    select '2022-01-16' as dt, 1 as sign_in from dual union
    select '2022-01-17' as dt, 1 as sign_in from dual union
    select '2022-01-18' as dt, 1 as sign_in from dual
),
tmp as (
select dt, sign_in,row_number()over(order by dt) as rn from t ) ,
tmp1 (dt, sign_in,lxqd,rn) as
(select dt, sign_in ,sign_in as lxqd , rn from tmp
where rn=1
union all
select b.dt,b.sign_in, decode(b.sign_in,0,0, a.lxqd+1) as lxqd,b.rn from tmp1 a, tmp b
where a.rn+1=b.rn)
select  * from tmp1

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表