ITPUB论坛-中国最专业的IT技术社区

 
 注册
热搜:
查看: 43785|回复: 46

[精华] 受lastwinner邀请,尝试作答第三届SQL大赛第一道题

[复制链接]
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
跳转到指定楼层
1#
发表于 2016-1-12 21:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 rollingpig 于 2016-1-12 22:45 编辑

Insert - 255168 row(s), executed in 37.773 sec.

思路都在注释中
  1. insert /*+append*/ into TICTACTOE
  2. with winbin as --列举8种赢的可能性的二进制表示,分别是三种独占一行,三种独占一列,两种对角线
  3. (select (4+2+1)*8*8 b1, (4+2+1)*8 b2, (4+2+1)*1 b3, --独占一行
  4.         (64+8+1)*4 b4, (64+8+1)*2 b5, (64+8+1)*1 b6, -- 独占一列
  5.         64*1+8*2+1*4 b7, 64*4+8*2+ 1*1 b8  --对角线
  6. from dual),
  7. p as (select --9个格子
  8. level num,  --第几个格子的10进制
  9. power(2,level-1) bin, --第几个格子的二进制
  10. power(10,9-level) str  --第几个格子的字符位
  11. from dual connect by level <10),
  12. X(nums,  --十进制表示
  13. bins, --二进制表示
  14. strs, -- 字符位
  15. len, --长度(本方第几个子)
  16. won --是否已经赢了(同时match winbin中的位置)
  17. ) as (
  18. select num,bin,str,1,0 from p --第一个开始
  19. union all
  20. select num+nums*100 --十进制表示,注意,由于各下一个,本方的下一个等于全局的下两个
  21. ,bin+bins --二进制
  22. ,str+strs --字符位置
  23.   ,len+1 --本方第几个子
  24. ,(case when bitand(bin+bins,b1)=b1  --注意binand用法, 如果已下子的二进制存在赢得3个位置,就证明本方赢了
  25.         or  bitand(bin+bins,b2)=b2
  26.         or  bitand(bin+bins,b3)=b3
  27.         or  bitand(bin+bins,b4)=b4
  28.         or  bitand(bin+bins,b5)=b5
  29.         or  bitand(bin+bins,b6)=b6
  30.         or  bitand(bin+bins,b7)=b7
  31.         or  bitand(bin+bins,b8)=b8
  32.   then 1  
  33.    else 0
  34. end)
  35.   from p,X,winbin
  36.   where X.won=0 --如果上个结果串赢了,就不必再下
  37.   and len<5 --最多5个
  38.   and bitand(bins,bin)=0 --不能重复下同一位置,注意bitand用法
  39.   )
  40.    select X.nums+O.nums*10 moves  -- 第二个人的需要移一位,相加,结果就是两个人下的结果
  41.      ,translate(X.strs+2*O.strs,'012','-XO') board --把第二个人的位置*2, 相加,得到012的位置串,用translate,把012分别改为 -,X,O
  42.      ,decode(X.won,1,'X',decode(O.won,1,'O','D')) as winner --这个简单,两个decode嵌套,case when可能跟好看
  43.      --, X.nums,O.nums
  44.     from X,X O --X是第一个人,O是第二个人
  45.      where
  46.       bitand(X.bins,O.bins)=0 --注意bitand, 这里表示没有重复下同一个格子
  47.       and (
  48.      (X.len in(5) and O.len in(4)  and O.won=0 ) --下到9个,当然,第二个人显然不能赢
  49.      or (X.len in(3,4) and O.len in(2,3) and X.len=O.len+1 and X.won=1 and O.won=0) --第一个人赢,下到
  50.      or (X.len in(3,4) and O.len in(3,4) and X.len=O.len and X.won=0 and O.won=1) --第二个人赢
  51.      )
复制代码
论坛徽章:
394
阿斯顿马丁
日期:2014-01-03 13:53:522014年世界杯参赛球队:喀麦隆
日期:2014-07-11 12:10:53马上有对象
日期:2014-04-09 16:19:542014年世界杯参赛球队: 洪都拉斯
日期:2014-06-25 08:25:55itpub13周年纪念徽章
日期:2014-09-28 10:55:55itpub13周年纪念徽章
日期:2014-10-01 15:27:22itpub13周年纪念徽章
日期:2014-10-09 12:04:18马上有钱
日期:2014-10-14 21:37:37马上有钱
日期:2015-01-22 00:39:13喜羊羊
日期:2015-02-20 22:26:07
2#
发表于 2016-1-12 21:34 | 只看该作者
老猪风采依旧

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
3#
发表于 2016-1-12 21:35 | 只看该作者
本帖最后由 rollingpig 于 2016-1-12 22:46 编辑

第二个,没有本质区别。
  1. --insert /*+append*/ into TICTACTOE
  2. select count(*) from(
  3. with p as (select --9个格子
  4. level num,  --第几个格子的10进制
  5. power(2,level-1) bin, --第几个格子的二进制
  6. power(10,9-level) str  --第几个格子的字符位
  7. from dual connect by level <10),
  8. X(nums,  --十进制表示
  9. bins, --二进制表示
  10. strs, -- 字符位
  11. len, --长度(本方第几个子)
  12. won --是否已经赢了(同时match winbin中的位置)
  13. ) as (
  14. select num,bin,str,1,0 from p --第一个开始
  15. union all
  16. select num+nums*100 --十进制表示,注意,由于各下一个,本方的下一个等于全局的下两个
  17. ,bin+bins --二进制
  18. ,str+strs --字符位置
  19.   ,len+1 --本方第几个子
  20. ,(case when  --注意binand用法, 如果已下子的二进制存在赢得3个位置,就证明本方赢了
  21.             bitand(bin+bins,7*64)=7*64  --第一行
  22.         or  bitand(bin+bins,7*8)=7*8  --第二行
  23.         or  bitand(bin+bins,7)=7  --第三行
  24.         or  bitand(bin+bins,73*4)=73*4 --第一列
  25.         or  bitand(bin+bins,73*2)=73*2 --第二列
  26.         or  bitand(bin+bins,73)=73 --第三列
  27.         or  bitand(bin+bins,64+8*2+1*4)=64+8*2+1*4 --左上右下对角线
  28.         or  bitand(bin+bins,64*4+8*2+1)=64*4+8*2+1 --左下右上对角线
  29.   then 1  
  30.    else 0
  31. end)
  32.   from p,X
  33.   where X.won=0 --如果上个结果串赢了,就不必再下
  34.   and len<5 --最多5个
  35.   and bitand(bins,bin)=0 --不能重复下同一位置,注意bitand用法
  36.   )
  37.    --create table dmp as
  38.    select X.nums+O.nums*10 moves  -- 第二个人的需要移一位,相加,结果就是两个人下的结果
  39.      ,translate(lpad(X.strs+2*O.strs,9,0),'012','-XO') board --把第二个人的位置*2, 相加,得到012的位置串,用translate,把012分别改为 -,X,O
复制代码

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
4#
发表于 2016-1-12 22:18 | 只看该作者
本帖最后由 rollingpig 于 2016-1-12 22:47 编辑

无注释版
  1. with CELL as (select level M,  power(2,level-1) B, power(10,9-level) P from dual connect by level <10),
  2. MOVE(MV,  BI,  PO,  RD,  WON  ) as (
  3. select M,B,P,1,0 from CELL
  4. union all
  5. select M+MV*100  ,B+BI ,P+PO,RD+1
  6. ,(case when bitand(B+BI,7*64)=7*64 or  bitand(B+BI,7*8)=7*8   or bitand(B+BI,7)=7  
  7.         or   bitand(B+BI,73*4)=73*4 or  bitand(B+BI,73*2)=73*2 or bitand(B+BI,73)=73
  8.         or   bitand(B+BI,64+8*2+1*4)=64+8*2+1*4  or bitand(B+BI,64*4+8*2+1)=64*4+8*2+1
  9.   then 1    else 0 end)
  10.   from CELL C,MOVE M  where WON=0 and RD<5 and bitand(BI,B)=0 )
  11. select X.MV+O.MV*10 moves,translate(lpad(X.PO+2*O.PO,9,0),'012','-XO') board  ,decode(X.WON,1,'X',decode(O.WON,'O','D')) as winner
  12.     from MOVE X,MOVE O
  13.     where bitand(X.BI,O.BI)=0 and (
  14.         (X.RD in(3,4) and O.RD in(2,3) and X.RD=O.RD+1 and X.WON=1 and O.WON=0)
  15.      or (X.RD in(3,4) and O.RD in(3,4) and X.RD=O.RD   and X.WON=0 and O.WON=1)
  16.      or (X.RD =5 and O.RD =4 and O.WON=0) )
复制代码

使用道具 举报

回复
论坛徽章:
480
榜眼
日期:2015-09-09 10:34:21秀才
日期:2015-11-23 10:03:12秀才
日期:2015-11-23 10:03:12秀才
日期:2015-11-23 10:03:12秀才
日期:2015-11-23 10:03:12秀才
日期:2015-11-23 10:03:12秀才
日期:2015-11-23 10:03:12秀才
日期:2015-11-23 10:03:12状元
日期:2015-11-23 10:04:09举人
日期:2015-11-23 10:04:09
5#
发表于 2016-1-12 22:19 | 只看该作者
有意思,先生成一个人的下法再拼成两个人的棋局,这种思路第一次见到。
老猪肯定没玩过瘾,请移步:
/thread-2050490-1-2.html

使用道具 举报

回复
论坛徽章:
394
阿斯顿马丁
日期:2014-01-03 13:53:522014年世界杯参赛球队:喀麦隆
日期:2014-07-11 12:10:53马上有对象
日期:2014-04-09 16:19:542014年世界杯参赛球队: 洪都拉斯
日期:2014-06-25 08:25:55itpub13周年纪念徽章
日期:2014-09-28 10:55:55itpub13周年纪念徽章
日期:2014-10-01 15:27:22itpub13周年纪念徽章
日期:2014-10-09 12:04:18马上有钱
日期:2014-10-14 21:37:37马上有钱
日期:2015-01-22 00:39:13喜羊羊
日期:2015-02-20 22:26:07
6#
发表于 2016-1-12 22:41 | 只看该作者
newkid 发表于 2016-1-12 22:19
有意思,先生成一个人的下法再拼成两个人的棋局,这种思路第一次见到。
老猪肯定没玩过瘾,请移步:
http ...

可惜剪枝在最后一步

使用道具 举报

回复
论坛徽章:
264
布鲁克
日期:2016-10-08 10:06:50秀才
日期:2016-05-20 15:09:32射手座
日期:2016-05-26 14:02:50双子座
日期:2016-05-25 16:05:44白羊座
日期:2016-05-23 11:49:19双鱼座
日期:2016-04-29 17:13:05秀才
日期:2016-04-29 15:03:39秀才
日期:2016-04-29 15:04:10技术图书徽章
日期:2016-04-29 15:04:10秀才
日期:2016-03-28 10:21:13
7#
发表于 2016-1-12 22:47 | 只看该作者
  欢迎常来逛逛!

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
8#
发表于 2016-1-12 22:48 | 只看该作者
前面也有剪的。

这次没追求性能,主要追求写起来代码漂亮

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
9#
发表于 2016-1-12 23:06 | 只看该作者
重看了一下,发现之前代码两处错误,第二个decode少了参数,translate里面的原始字符串忘了前面补0. 还是老了。

使用道具 举报

回复
论坛徽章:
10000
地主之星
日期:2015-07-20 17:15:36地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-09-01 17:59:09地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-09-01 14:14:25地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58
10#
发表于 2016-1-13 00:28 | 只看该作者

使用道具 举报

回复

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

本版积分规则

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