本博客是来源CSDN BBS上一个问题。原问题如下:

从系统时间往前M天内,有连续M天交易笔数小于B笔的商户。

表设计:

CREATE TABLE prm_tbl(zoneno NUMBER, last_days NUMBER, min_days NUMBER, min_trans NUMBER);
CREATE TABLE acc_tbl(d_date DATE, merch NUMBER, cnt NUMBER);
CREATE TABLE merch_list(merch NUMBER, zoneno NUMBER);

prm_tbl定义某问题描述中的三个参数。

acc_tbl是交易记录表,假如商户在某天没有交易,则该表没有数据。

merch_list是商户和区域的关联表。某区域内有一个或多个商户。

测试数据如下:

$sh@ORCL> select * from prm_tbl;ZONENO LAST_DAYS MIN_DAYS MIN_TRANS
------ --------- -------- ---------1         5        2         62         5        3         6Elapsed: 00:00:00.05
$sh@ORCL> select * from acc_tbl order by d_date desc;D_DATE         MERCH        CNT
--------- ---------- ----------
03-JAN-14          1          7
02-JAN-14          1          6
01-JAN-14          1          7
31-DEC-13          1          4
30-DEC-13          1          7
29-DEC-13          1          3Elapsed: 00:00:00.01
$sh@ORCL> select * from merch_list;MERCH ZONENO
----- ------1      12      2

可以看出merch = 1是不符合条件的,他小于B笔交易的天数不连续。而merch = 2在这段时间没有交易,显然是符合条件的。

用Java, PL/SQL等procedual based语言通过循环可以解决该问题,但这里只讨论基于集合的SQL来解决问题。在数据库中,通常基于集合的运算比“基于过程”的效率高!

需要解决的几个问题:

1. 交易在时间和区域两个维度上是稀疏的,即商户可能在某个区域某段时间没有交易。这是一个双维度的“数据稠化”问题。

2. 连续N天如何解决?

问题1的解决办法在我另一个博客中已有介绍 http://blog.csdn.net/chncaesar/article/details/17321267,这里的问题更复杂,请看SQL:

with all_data as(
select ml.zoneno, ml.merch, date_id, nvl(tran_cnt,0) tran_cnt, row_number() over(partition by ml.zoneno, ml.merch order by date_id desc) rn from
(select acc.merch, dates.date_id, nvl(acc.cnt,0) tran_cnt  from acc_tbl acc partition by (merch) right outer join (select trunc(sysdate) - level date_id from dual connect by level <= (select max(last_days) from prm_tbl)) dates
on acc.d_date=dates.date_id) merch_dates partition by (merch, date_id) right outer join merch_list ml on merch_dates.merch=ml.merch
)
select * from all_data;

但是问题1还没有完全解决,每个区域的过去M天,M取值是不一样的,我们还需要一个连接来完成这事。

with all_data as(
select ml.zoneno, ml.merch, date_id, nvl(tran_cnt,0) tran_cnt, row_number() over(partition by ml.zoneno, ml.merch order by date_id desc) rn from
(select acc.merch, dates.date_id, nvl(acc.cnt,0) tran_cnt  from acc_tbl acc partition by (merch) right outer join (select trunc(sysdate) - level date_id from dual connect by level <= (select max(last_days) from prm_tbl)) dates
on acc.d_date=dates.date_id) merch_dates partition by (merch, date_id) right outer join merch_list ml on merch_dates.merch=ml.merch
),
filtered_data as(
select ad.*, pt.min_days,pt.min_trans
from all_data ad, prm_tbl pt
where ad.zoneno=pt.zoneno
and ad.rn <= pt.last_days
)
select * from filtered_data
order by zoneno, merch, date_id desc;

问题1解决。这里再给出通过笛卡尔积来实现“数据稠化”的SQL:

  SELECT pt.zoneno, ml.merch, date_id, pt.last_days,pt.min_days, pt.min_transfrom prm_tbl pt, merch_list ml,(SELECT zones.zoneno, dates.date_id, row_number() over(partition by zones.zoneno order by dates.date_id desc) rn FROM(SELECT DISTINCT zoneno FROM prm_tbl) zones,(SELECT trunc(SYSDATE) - LEVEL date_id FROM dual CONNECT BY LEVEL <= (SELECT MAX(last_days) FROM prm_tbl)) dates) zone_date_vWHERE zone_date_v.zoneno=pt.zonenoAND zone_date_v.rn <= pt.last_daysAND pt.zoneno=ml.zoneno;

下面考虑问题2,现在的结果集已经包含过去M天的所有数据,连续N天的问题。请看如下SQL:

sum((case when tran_cnt <= min_trans then 1 else 0 end)) over(partition by zoneno, merch) sum_ind

计算各区域每个商户交易量少于B的天数。连续性的解决请看如下SQL:

with all_data as(
select ml.zoneno, ml.merch, date_id, nvl(tran_cnt,0) tran_cnt, row_number() over(partition by ml.zoneno, ml.merch order by date_id desc) rn from
(select acc.merch, dates.date_id, nvl(acc.cnt,0) tran_cnt  from acc_tbl acc partition by (merch) right outer join (select trunc(sysdate) - level date_id from dual connect by level <= (select max(last_days) from prm_tbl)) dates
on acc.d_date=dates.date_id) merch_dates partition by (merch, date_id) right outer join merch_list ml on merch_dates.merch=ml.merch
),
filtered_data as(
select ad.*, pt.min_days,pt.min_trans,
(case when ad.tran_cnt <= pt.min_trans then 1 else 0 end) ind,
sum((case when ad.tran_cnt <= pt.min_trans then 1 else 0 end)) over(partition by ad.zoneno, ad.merch) sum_ind
from all_data ad, prm_tbl pt
where ad.zoneno=pt.zoneno
and ad.rn <= pt.last_days
),
--select * from filtered_data;
sparse_data as(
select zoneno, merch,rn, nvl(lag(rn, 1) over(partition by zoneno, merch order by date_id desc),0) pre_rn
from filtered_data
where ind=1
and sum_ind >= min_days
)
select distinct zoneno, merch from sparse_data
where rn - pre_rn =1;ZONENO      MERCH
---------- ----------2          2

在这里,rn - pre_rn=1即表示是连续的。

SQL解决过去M天内连续N天符合某条件问题相关推荐

  1. SQL实战篇:SQL解决连续X天的问题

    上一节内容,通过用户留存率的案例,讲解了解决近X天问题的思路,接下来,在本节内容来看看关于连续X天的问题,该类问题是面试和实际业务中经常需要解决的问题. 首先对连续指标.做个定义,如下: 1日连续:当 ...

  2. 如何设计登录接口,十分钟内连续登录5次失败,需要等待30分钟才能登录

    正常业务里的实现不能这样搞,合适的方法是走缓存,比如使用redis,我当时就只有原生Java API能用,请大家把这个当成算法题来看待 常言道:字数越短问题越大.   今天阿里的面试官小哥哥让我实现一 ...

  3. c语言for循环多条件判断,解决在for循环内判断条件多次执行

    最近遇到的这个问题,就是在for循环内if判断的条件会多次执行. 例如,在返回的30数据中,a条目是第7条则会进行30次判断,弹出29次查无数据,也就是要点击29次关闭alert,很是让人不爽. 有了 ...

  4. SQL解决去重问题(在线超10min中的人数等)

    SQL解决去重问题(在线超10min中的人数等) 内容目录 SQL解决去重问题(在线超10min中的人数等) 一.描述 二.求解 1.思路1 2.思路2 三.牛客的SQL33:直播各科出勤率 一.描述 ...

  5. SQL反模式笔记17——用一条sql解决复杂问题

    目标:检查sql查询次数 反模式:试图用一条sql解决复杂问题 结果是:性能很低,而且往往得到了一个笛卡尔积. 解决方案:分而治之 用多个sql得到数据,再进行整合.或者union多个sql的结果. ...

  6. 你真的会玩SQL吗?和平大使 内连接、外连接

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  7. 创建存储过程时出现的This function has none of DETERMINISTIC, NO SQL解决办法

    This function has none of DETERMINISTIC, NO SQL解决办法 创建存储过程时 出错信息: ERROR 1418 (HY000): This function ...

  8. This function has none of DETERMINISTIC, NO SQL解决办法

    This function has none of DETERMINISTIC, NO SQL解决办法 创建存储过程时 出错信息: ERROR 1418 (HY000): This function ...

  9. 高手过招:用SQL解决环环相扣的刑侦推理问题(苏旭辉版本)

    苏旭晖,网名 newkid,ITPUB 开发版资深版主,SQL开发专家 本文是继 杨长老 刑侦高考:如何用SQL解决环环相扣的刑侦推理问题  之后,苏旭辉的一个版本,希望大家能够在高手的过招中,看到喜 ...

  10. 高手过招:用SQL解决环环相扣的刑侦推理问题(罗海雄版本)

    关注我们获得更多精彩内容! 本文是继 杨长老 刑侦高考:如何用SQL解决环环相扣的刑侦推理问题  之后(点击阅读原文查看历史信息),罗海雄老师提供了一个带注释的版本,希望初学者也能够直接看懂,不仅仅是 ...

最新文章

  1. beta阶段140字评论
  2. EOS 智能合约源代码解读 (4)symbol.hpp
  3. QT的QCache类的使用
  4. MFC载入JPG图片
  5. 作者:刘昂(1990-),男,中国科学院计算机网络信息中心工程师
  6. 程序员该如何合理安排时间呢?
  7. 【BZOJ-3721】Final Bazarek 贪心
  8. HTML5的设计目的是为了在移动设备上支持多媒体
  9. 怎么看待苹果公司要求分成微信、知乎打赏32%?
  10. mcgs 安装没有权限_我的电脑为什么不能安装mcgs组态软件
  11. 空间战场态势感知系统
  12. LTE IDLE DRX和CDRX
  13. iOS性能优化的几个方向
  14. confusion matix
  15. 蓝桥杯十大常见天阶功法——炎之呼吸.叁之型.动态规划--(上篇)
  16. 外币记账及重估总账余额表变化(下)
  17. 项目经理的能力模型和能力提升的方法
  18. 如何把项目部署到腾讯云服务器(附带常见错误)
  19. python爬取微信群聊内容_再不学Python 你就被同龄人甩开了吗?
  20. 使命召唤手游如何在电脑上玩 使命召唤手游模拟器教程

热门文章

  1. docker加了--insecure-registry后docker启动报错Failed to start Docker Application Container Engine.
  2. python判断正数负数_python 负数变正数
  3. 使用adb工具向android设备上传/下载文件
  4. java bss_数据段、代码段、堆栈段、BSS段的区别
  5. 坐标测量机的定位误差和测长不确定度有何区别,如何表示?
  6. 大家来找茬源码(微擎) -- 流量主
  7. showVideo C#版 摄像头驱动程序
  8. [渝粤教育] 西南科技大学 汉语写作 在线考试复习资料
  9. tzoj 3847 Mowing the Lawn (单调队列 )
  10. csgo 机器人模式_csgo怎么加机器人