楼主: newkid

[精华] 深夜独霸, 轮到我出个题目了——算24点的SQL解法

[复制链接]
论坛徽章:
24
萤石
日期:2013-01-03 16:13:11海蓝宝石
日期:2013-04-23 17:06:35红宝石
日期:2013-05-17 17:32:35SQL大赛参与纪念
日期:2013-12-06 14:03:45马上有对象
日期:2014-02-18 16:44:08马上有车
日期:2014-02-27 15:22:45优秀写手
日期:2014-03-22 06:00:12马上有房
日期:2014-03-26 19:40:00巨蟹座
日期:2015-10-18 17:42:41
131#
发表于 2011-5-13 17:26 | 只看该作者
WITH NUM1 AS(

       SELECT DECODE (E.O,
       '+',A.N+B.N,
       '-',A.N-B.N,
       '*',A.N*B.N,
       '/',A.N/B.N
       ) AS N1,C.N N2,D.N N3,'('||A.N||E.O||B.N||')' S
       FROM T24 A,T24 B,T24 C,T24 D ,O24 E
       WHERE A.N NOT IN (B.N,C.N,D.N)
       AND B.N NOT IN (C.N,D.N)
       AND C.N <> D.N),
       -----1111模式
      NUM2 AS( SELECT DECODE(E.O,
       '+',N1+N2,
       '-',N1-N2,
       '*',N1*N2,
       '/',N1/N2
       ) AS M3,N3 M4,'('||S||E.O||N2||')' M5 ,TO_CHAR(N3) M6
        FROM NUM1,O24 E
        UNION ALL---11*11模式
        SELECT DECODE(E.O,
       '+',N3+N2,
       '-',N3-N2,
       '*',N3*N2,
       '/',N3/N2
       ) AS M3,N1 M4,'('||N3||E.O||N2||')' M5,S M6
        FROM NUM1,O24 E),
        
      NUM3 AS(  SELECT DECODE(E.O,
        '+',M3+M4,
        '-1',M3-M4,
        '*',M3*M4,
        '/',M3/M4
        ) AS TOTAL,M5||E.O||M6 TS
         FROM NUM2,O24 E)
         SELECT * FROM NUM3 WHERE TOTAL=24

按别人的方法 终于把代码写出来了   没有去除重复    也算第一次完成任务 哈哈 开心

使用道具 举报

回复
论坛徽章:
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
132#
 楼主| 发表于 2011-5-13 22:04 | 只看该作者
原帖由 ccceleven 于 2011-5-13 17:26 发表
WITH NUM1 AS(

       SELECT DECODE (E.O,
       '+',A.N+B.N,
       '-',A.N-B.N,
       '*',A.N*B.N,
       '/',A.N/B.N
       ) AS N1,C.N N2,D.N N3,'('||A.N||E.O||B.N||')' S
       FROM T24 A,T24 B,T24 C,T24 D ,O24 E
       WHERE A.N NOT IN (B.N,C.N,D.N)
       AND B.N NOT IN (C.N,D.N)
       AND C.N  D.N),
       -----1111模式
      NUM2 AS( SELECT DECODE(E.O,
       '+',N1+N2,
       '-',N1-N2,
       '*',N1*N2,
       '/',N1/N2
       ) AS M3,N3 M4,'('||S||E.O||N2||')' M5 ,TO_CHAR(N3) M6
        FROM NUM1,O24 E
        UNION ALL---11*11模式
        SELECT DECODE(E.O,
       '+',N3+N2,
       '-',N3-N2,
       '*',N3*N2,
       '/',N3/N2
       ) AS M3,N1 M4,'('||N3||E.O||N2||')' M5,S M6
        FROM NUM1,O24 E),
        
      NUM3 AS(  SELECT DECODE(E.O,
        '+',M3+M4,
        '-1',M3-M4,
        '*',M3*M4,
        '/',M3/M4
        ) AS TOTAL,M5||E.O||M6 TS
         FROM NUM2,O24 E)
         SELECT * FROM NUM3 WHERE TOTAL=24

按别人的方法 终于把代码写出来了   没有去除重复    也算第一次完成任务 哈哈 开心


很简洁,就怕有误差:

WITH N1 AS (SELECT 1/3 N FROM DUAL)
,N2 AS (SELECT N*3 N FROM N1)
SELECT * FROM N2;


         N
----------
         1


WITH N1 AS (SELECT 1/3 N FROM DUAL)
,N2 AS (SELECT N*3 N FROM N1)
SELECT * FROM N2 WHERE N=1;

no rows selected

使用道具 举报

回复
论坛徽章:
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
133#
 楼主| 发表于 2011-5-13 22:20 | 只看该作者
呵呵,回头看了一下自己的答案其实也是分步求结果的......
其实哪怕一步完成也不能避免误差:
select 1 from dual where 1/3*3=1;

不知道有什么好办法。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
134#
发表于 2011-5-13 23:04 | 只看该作者
原帖由 newkid 于 11-5-13 22:20 发表
呵呵,回头看了一下自己的答案其实也是分步求结果的......
其实哪怕一步完成也不能避免误差:
select 1 from dual where 1/3*3=1;

不知道有什么好办法。


round嘛……

使用道具 举报

回复
论坛徽章:
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
135#
 楼主| 发表于 2011-5-14 01:57 | 只看该作者
131楼在1,4,5,6出不了结果,原来以为是误差的原因,其实是少了减法和除法的对调。修改:

WITH NUM1 AS(
SELECT DECODE (E.O,
               '+',A.N+B.N,
               '-',A.N-B.N,
               '*',A.N*B.N,
               '/',A.N/B.N
               ) AS N1
       ,C.N N2
       ,D.N N3
       ,'('||A.N||E.O||B.N||')' S
  FROM T24 A,T24 B,T24 C,T24 D ,O24 E
  WHERE A.N NOT IN (B.N,C.N,D.N)
       AND B.N NOT IN (C.N,D.N)
       AND C.N <> D.N),
       -----1111模式
NUM2 AS(
SELECT DECODE(E.O,
               '+',N1+N2,
               '-',N1-N2,
               '*',N1*N2,
               '/',N1/N2
               ) AS M3
       ,N3 M4
       ,'('||S||E.O||N2||')' M5
       ,TO_CHAR(N3) M6
FROM NUM1,O24 E
UNION ALL---11*11模式
SELECT DECODE(E.O,
              '+',N3+N2,
              '-',N3-N2,
              '*',N3*N2,
              '/',N3/N2
              ) AS M3
        ,N1 M4
        ,'('||N3||E.O||N2||')' M5
        ,S M6
  FROM NUM1,O24 E
UNION ALL
SELECT DECODE(E.O,
               '-',N2-N1,
               '/',N2/N1
               ) AS M3
       ,N3 M4
       ,'('||N2||E.O||S||')' M5
       ,TO_CHAR(N3) M6
FROM NUM1,O24 E
WHERE E.O IN ('-','/') AND (N1<>0 OR E.O='-')
  ),
NUM3 AS(  
SELECT DECODE(E.O,
              '+',M3+M4,
              '-1',M3-M4,
              '*',M3*M4,
              '/',M3/M4
              ) AS TOTAL
       ,M5||E.O||M6 TS
FROM NUM2,O24 E
UNION ALL
SELECT DECODE(E.O,
              '-1',M4-M3,
              '/',M4/M3
              ) AS TOTAL
       ,M6||E.O||M5 TS
FROM NUM2,O24 E
WHERE E.O IN ('-','/') AND (M3<>0 OR E.O='-')
)
SELECT * FROM NUM3 WHERE TOTAL=24;

     24 6/((5/4)-1)
     24 4/(1-(5/6))

使用道具 举报

回复
论坛徽章:
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
136#
 楼主| 发表于 2011-5-14 04:20 | 只看该作者
下面这个思路是前几天“影之哀伤”提出来的,看起来挺像递归但是却用不了递归WITH,因为递归WITH里面只有最近一层数据可见。看谁有办法改出来。

WITH v1 AS (SELECT CHR(ROW_NUMBER() OVER(ORDER BY n)) id,n,to_char(n) s FROM t24)
,v2 AS (
SELECT id,n,s
FROM v1
UNION ALL
SELECT a.id||b.id id
      ,DECODE (e.o,
              '+',a.n+b.n,
              '-',a.n-b.n,
              '*',a.n*b.n,
              '/',a.n/b.n
              ) n
      ,'('||a.s||e.o||b.s||')' s
FROM v1 a,v1 b,o24 e
WHERE a.id<>b.id AND (a.n<>0 OR e.o<>'/')
)
,v3 AS (
SELECT id,n,s
FROM v2
UNION ALL
SELECT a.id||b.id id
      ,DECODE (e.o,
              '+',a.n+b.n,
              '-',a.n-b.n,
              '*',a.n*b.n,
              '/',a.n/b.n
              ) n
      ,'('||a.s||e.o||b.s||')' s
FROM v2 a,v2 b,o24 e
WHERE TRANSLATE(a.id,'$'||b.id,'$')=a.id AND (b.n<>0 OR e.o<>'/')
)
,v AS (
SELECT DECODE (e.o,
              '+',a.n+b.n,
              '-',a.n-b.n,
              '*',a.n*b.n,
              '/',a.n/b.n
              ) n
      ,'('||a.s||e.o||b.s||')' s
FROM v3 a,v3 b,o24 e
WHERE TRANSLATE(a.id,'$'||b.id,'$')=a.id AND (b.n<>0 OR e.o<>'/')
      AND LENGTH(a.id||b.id)=4
)
SELECT * FROM v WHERE n=24;

使用道具 举报

回复
论坛徽章:
2
2011新春纪念徽章
日期:2011-01-04 10:38:212011新春纪念徽章
日期:2011-02-18 11:43:33
137#
发表于 2011-5-15 00:01 | 只看该作者
大师,貌似还没有人用了我说的递归的方法的吧?

输出的问题上,得再弄个procedure来表示就好了。近期忙,有时间做这个就好了

使用道具 举报

回复
论坛徽章:
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
138#
 楼主| 发表于 2011-5-15 05:19 | 只看该作者
原帖由 影之哀伤 于 2011-5-15 00:01 发表
大师,貌似还没有人用了我说的递归的方法的吧?

输出的问题上,得再弄个procedure来表示就好了。近期忙,有时间做这个就好了


我楼上的方法不就是了吗?你可以看到我每层的写法都基本上是一样的(可以做到完全一样),只是ORACLE现在的递归WITH 有局限,所以不得不手工写为三层。
你可以自己用PLSQL实现看看。

使用道具 举报

回复
论坛徽章:
2
2011新春纪念徽章
日期:2011-01-04 10:38:212011新春纪念徽章
日期:2011-02-18 11:43:33
139#
发表于 2011-5-15 12:37 | 只看该作者
原帖由 newkid 于 2011-5-15 05:19 发表


我楼上的方法不就是了吗?你可以看到我每层的写法都基本上是一样的(可以做到完全一样),只是ORACLE现在的递归WITH 有局限,所以不得不手工写为三层。
你可以自己用PLSQL实现看看。


我抱歉我没好好看,递归也SQL不会

你能把举个例子,把输出结果发出来么?
看看结果是不是去重了的。(1,2,3,4 is OK)

使用道具 举报

回复
论坛徽章:
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
140#
 楼主| 发表于 2011-5-15 23:06 | 只看该作者
没法全部去除重复,可以部分去除:

WITH v1 AS (SELECT CHR(ROW_NUMBER() OVER(ORDER BY n)) id,n,to_char(n) s FROM t24)
,v2 AS (
SELECT id,n,s
FROM v1
UNION ALL
SELECT a.id||b.id id
      ,DECODE (e.o,
              '+',a.n+b.n,
              '-',a.n-b.n,
              '*',a.n*b.n,
              '/',a.n/b.n
              ) n
      ,'('||a.s||e.o||b.s||')' s
FROM v1 a,v1 b,o24 e
WHERE a.id<>b.id AND (a.n<>0 OR e.o<>'/') AND (e.o NOT IN ('+','*') OR a.id<b.id)
)
,v3 AS (
SELECT id,n,s
FROM v2
UNION ALL
SELECT a.id||b.id id
      ,DECODE (e.o,
              '+',a.n+b.n,
              '-',a.n-b.n,
              '*',a.n*b.n,
              '/',a.n/b.n
              ) n
      ,'('||a.s||e.o||b.s||')' s
FROM v2 a,v2 b,o24 e
WHERE TRANSLATE(a.id,'$'||b.id,'$')=a.id AND (b.n<>0 OR e.o<>'/') AND (e.o NOT IN ('+','*') OR a.id<b.id)
)
,v AS (
SELECT DECODE (e.o,
              '+',a.n+b.n,
              '-',a.n-b.n,
              '*',a.n*b.n,
              '/',a.n/b.n
              ) n
      ,'('||a.s||e.o||b.s||')' s
FROM v3 a,v3 b,o24 e
WHERE TRANSLATE(a.id,'$'||b.id,'$')=a.id AND (b.n<>0 OR e.o<>'/') AND (e.o NOT IN ('+','*') OR a.id<b.id)
      AND LENGTH(a.id||b.id)=4
)
SELECT * FROM v WHERE n=24;


输出有79行,你自己试一下就知道了, 比如:
(((1*4)*2)*3)

        24
(((1*4)*3)*2)

        24
(((2*3)/1)*4)

        24
(((2*3)*4)/1)

        24
(((2*4)/1)*3)

        24
(((2*4)*3)/1)

        24
(((2/1)*3)*4)

        24
(((2/1)*4)*3)

使用道具 举报

回复

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

本版积分规则 发表回复

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