查看: 18923|回复: 43

递归with真是个好东西

[复制链接]
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
跳转到指定楼层
1#
发表于 2010-12-10 01:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
装上11g, 先玩一下递归with语句, 真是个好东西。
以前觉得单行SQL实现很费劲的几个问题, 现在解决起来轻松多了。



把做过的几个问题在这里归纳一下:

1. 阶乘。  2#,12#

2. 质因数分解。  我的在3#, 很笨。  请看5# newkid的版本

3. 2个数的gcd. 15#

4. 多个数的gcd.  17#

5. 多个数的lcm.  18# 简单递推版本,  23# newkid的辗转相除版本

6. 菲波纳契数列.  19#

[ 本帖最后由 tree_new_bee 于 2010-12-11 09:37 编辑 ]
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
2#
 楼主| 发表于 2010-12-10 01:28 | 只看该作者
1. 阶乘。

以前用connect by来实现,性能到了8,9,就已经不可接受了。 用with语句写一下, 性能很强劲!

with targ as (select 6 d from dual)
,t as (select rownum n from targ connect by level<=30)
, prod(lastnum, lastprod) as
(select min(n), min(n)  from t union all
select n, n*lastprod from t, prod where n = prod.lastnum+1
)
select * from prod where lastnum = (select max(n) from t)


   LASTNUM   LASTPROD
---------- ----------
         6        720

Executed in 0.047 seconds

SQL>

   LASTNUM   LASTPROD
---------- ----------
        30 2.65252859

Executed in 0.125 seconds

SQL>

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
3#
 楼主| 发表于 2010-12-10 01:32 | 只看该作者
2. 质因数分解:

初练, 感觉到写的很笨重, 不过运行的效果不错。

with t as (select 720 d from dual)
,t1 as (select rownum rn, rownum+1 n from t connect by level<d)
, fact(f_rn, f_n, f_num, canmod) as (
select 1, 2, d, sign(mod(d,2)) from t
union all
select rn, decode(canmod,0, f_n, f_n+1), decode(canmod,0, f_num/f_n, f_num),
sign(mod(decode(canmod,0, f_num/f_n, f_num), decode(canmod,0, f_n, f_n+1)))
from t1, fact where  rn = f_rn + 1  and f_num>1
)
select f_n from fact  where  canmod=0


11  /

       F_N
----------
         2
         2
         2
         2
         3
         3
         5

7 rows selected

Executed in 0.156 seconds

SQL>

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
4#
 楼主| 发表于 2010-12-10 01:34 | 只看该作者
先不玩了, 睡觉去。

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
5#
发表于 2010-12-10 03:23 | 只看该作者
哈哈,就知道你会喜欢,希望你玩出新意思来!

质因子分解挺有意思,我也来献丑:
WITH t(c,n,m,r) AS (
SELECT 1,2,720,1 FROM DUAL
UNION ALL
SELECT c+1
      ,CASE WHEN MOD(m,n)>0 THEN n+1 ELSE n END
      ,CASE WHEN MOD(m,n)>0 THEN m ELSE m/n END
      ,MOD(m,n)
  FROM t
WHERE c<720 AND m>1
)
SELECT n FROM t WHERE r=0;

前阵子我写了个辗转相除法求n个数的最小公倍数,你要不要来试一下?

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
6#
发表于 2010-12-10 03:26 | 只看该作者
阶乘用CONNECT BY也不差嘛,你是怎么写的?

SELECT EXP(SUM(LN(LEVEL))) FROM DUAL CONNECT BY LEVEL<=10;

EXP(SUM(LN(LEVEL)))
-------------------
            3628800

Elapsed: 00:00:00.01

你还可以试一下MODEL。

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
7#
 楼主| 发表于 2010-12-10 08:12 | 只看该作者
原帖由 newkid 于 2010-12-10 03:23 发表
哈哈,就知道你会喜欢,希望你玩出新意思来!

质因子分解挺有意思,我也来献丑:
WITH t(c,n,m,r) AS (
SELECT 1,2,720,1 FROM DUAL
UNION ALL
SELECT c+1
      ,CASE WHEN MOD(m,n)>0 THEN n+1 ELSE n END
      ,CASE WHEN MOD(m,n)>0 THEN m ELSE m/n END
      ,MOD(m,n)
  FROM t
WHERE c1
)
SELECT n FROM t WHERE r=0;

前阵子我写了个辗转相除法求n个数的最小公倍数,你要不要来试一下?


我就说我写的看着那么笨重, 看你写的清楚多了。


刚琢磨这个东西, 对于哪个部分要怎么递归还总要来回瞎试, 所以写到最后逻辑都混乱了。

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
8#
 楼主| 发表于 2010-12-10 08:14 | 只看该作者
原帖由 newkid 于 2010-12-10 03:26 发表
阶乘用CONNECT BY也不差嘛,你是怎么写的?

SELECT EXP(SUM(LN(LEVEL))) FROM DUAL CONNECT BY LEVEL


这个powr+log的我知道。
我说的是以前提到过的那个sys_connect_by_path后数数的方式。

[ 本帖最后由 tree_new_bee 于 2010-12-10 08:24 编辑 ]

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
9#
 楼主| 发表于 2010-12-10 08:17 | 只看该作者
另外,请教一下啊newkid:
with子查询,在文档中称为subquery factoring clause
这里的 factoring 翻译成中文怎么说?

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
10#
发表于 2010-12-10 09:17 | 只看该作者
我把它称为“分解子查询”,自己杜撰的翻译。

使用道具 举报

回复

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

本版积分规则 发表回复

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