楼主: ~贝贝~

[精华] “盛拓传媒杯”SQL数据库编程大赛第四期评分及所有参赛选手答题公布!

[复制链接]
论坛徽章:
8
玉兔
日期:2015-11-16 10:18:00铁扇公主
日期:2015-10-27 21:47:42九尾狐狸
日期:2015-12-11 22:31:15
31#
发表于 2011-4-12 21:21 | 只看该作者
原帖由 rollingpig 于 2011-4-12 19:49 发表
两个表连接的效率未必比一个表+分析函数慢多少


这里这个特定的分析函数只需要一遍全表扫描(排序的前提下),所以应当会快,猜的

使用道具 举报

回复
论坛徽章:
5
生肖徽章2007版:鸡
日期:2008-01-02 17:35:532011新春纪念徽章
日期:2011-02-18 11:42:47SQL大赛参与纪念
日期:2011-04-13 12:08:17SQL数据库编程大师
日期:2011-04-13 12:09:01迷宫蛋
日期:2012-03-21 13:09:18
32#
发表于 2011-4-12 21:27 | 只看该作者
[quote]原帖由 [i]jvkojvko[/i] 于 2011-4-12 20:24 发表 [url=http://www.itpub.net/redirect.php?goto=findpost&pid=17540040&ptid=1417576][img]http://www.itpub.net/images/common/back.gif[/img][/url]
评审代号:SQL4-4
注释和代码(满分15):        14.9
思路(满分15):        14.6
性能(满分10):        5.6
完善-基本运行(30分):        29.9
完善-日期交叉测试(30分):        30
额外(奇思妙想附加分):        0
违规扣分:        0
总计:        95


我的扣分也就在性能上 [/quote]


这是我的:


/*
ITPUB“盛拓传媒杯”SQL数据库编程大赛第4题
数据库类型:Oracle,任意版本
解题思路:
1、先根据service_usage生成每天一条记录
        select to_date(:p_start_date, 'YYYYMMDD') + rownum - 1 mydate from dual         
        connect by rownum <=to_date(:p_end_date, 'YYYYMMDD') - to_date(:p_start_date, 'YYYYMMDD') + 1
        上面这个子查询与service_usage关联(mydate between a.start_date and a.end_date)可以生成每天一笔的消费记录
        count(distinct a.user_id) distinct_user_cnt 表示不同的用户数,如果1个用户1天消费多次算1个用户,根据这个数记算档次
        count(*) user_servcie_cnt 表示一天所有用户服务次数
2、与service_rates关联确定消费档次,按company_id, service_id,category_id汇总生成fee1,fee2,fee3,fee4,total_fee
3、与services关联得到service_name,与companies关联得到company_name
use_hash(f,g,h),use_hash(d,e),use_merge(a,b,c)这些全是为了大数量时优化,小数据量时可以不要。
*/
VAR p_start_date VARCHAR2(8);
VAR p_end_date VARCHAR2(8);
EXEC :p_start_date := '20100104';
EXEC :p_end_date := '20100130';

select /*+use_hash(f,g,h)*/f.company_id,h.company_name,f.service_id,g.service_name,fee1,fee2,fee3,fee4,total_fee
  from (select /*+use_hash(d,e)*/ d.company_id,d.service_id,
               sum(decode(e.category_id, 1, rate * user_servcie_cnt, null)) fee1,
               sum(decode(e.category_id, 2, rate * user_servcie_cnt, null)) fee2,
               sum(decode(e.category_id, 3, rate * user_servcie_cnt, null)) fee3,
               sum(decode(e.category_id, 4, rate * user_servcie_cnt, null)) fee4,
               sum(rate * user_servcie_cnt) total_fee
          from (select /*+use_merge(a,b,c)*/b.company_id,a.service_id,
                       count(distinct a.user_id) distinct_user_cnt, --表示不同的用户数,如果1个用户1天消费多次算1个用户,根据这个数记算档次
                       count(*) user_servcie_cnt --表示一天所有用户服务次数
                  from service_usage a,
                       service_users b,
                       (select to_date(:p_start_date, 'YYYYMMDD') + rownum - 1 mydate from dual         
                        connect by rownum <=to_date(:p_end_date, 'YYYYMMDD') - to_date(:p_start_date, 'YYYYMMDD') + 1) c
                 where a.user_id = b.user_id
                   and c.mydate between a.start_date and a.end_date --用于根据service_usage生成每天一笔的消费记录
                 group by b.company_id, a.service_id, c.mydate) d,service_rates e
         where d.company_id = e.company_id
           and d.service_id = e.service_id
           and d.distinct_user_cnt between e.user_count_min and e.user_count_max --确认消费档次
         group by d.company_id, d.service_id) f,services g,companies h --关联显示company_name,service_name
where f.company_id = h.company_id and f.service_id = g.service_id
order by f.company_id, f.service_id;

--结果
COMPANY_ID COMPANY_NAME                             SERVICE_ID SERVICE_NAME               FEE1       FEE2       FEE3       FEE4  TOTAL_FEE
---------- ---------------------------------------- ---------- -------------------- ---------- ---------- ---------- ---------- ----------
         1 company A                                         1 Service A                   320         90         90         20        520
         1 company A                                         2 Service B                    90         50        240        120        500
         2 company B                                         1 Service A                   198        136        252        224        810
         2 company B                                         2 Service B                   280                                         280


评审代号:SQL4-29
注释和代码(满分15):        11.25
思路(满分15):        11
性能(满分10):        3
完善-基本运行(30分):        30
完善-日期交叉测试(30分):        20
额外(奇思妙想附加分):        0
违规扣分:        
总计:        75.25

评语:结构清晰,性能稍差。计费的时候应该使用distinct_user_cnt而不是user_servcie_cnt,这个错误导致重复计费。

我太悲剧了,代码很简单,注释也有,为什么扣3.75分。
完善-日期交叉测试扣我10分,由于题目的歧义,我已经在注释里说明了。
我实际测试发现性能比高分的一些人也好很多,不知道为什么性能只有3分。

求评委解释一下啊。

[[i] 本帖最后由 yzsind 于 2011-4-12 21:28 编辑 [/i]]

使用道具 举报

回复
招聘 : 数据库管理员
论坛徽章:
83
IT宝贝
日期:2013-11-15 18:40:242015年新春福章
日期:2015-03-06 11:57:31美羊羊
日期:2015-03-04 14:48:58马上加薪
日期: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:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11
33#
 楼主| 发表于 2011-4-12 21:49 | 只看该作者
原帖由 yzsind 于 2011-4-12 21:27 发表
我太悲剧了,代码很简单,注释也有,为什么扣3.75分。
完善-日期交叉测试扣我10分,由于题目的歧义,我已经在注释里说明了。
我实际测试发现性能比高分的一些人也好很多,不知道为什么性能只有3分

性能这个分数基本还算中等的,呵呵,这期的性能分数普遍不高,这个分数是根据多位评委的打分求和然后求平均数得到的。
日期交叉测试方面的扣分,我核实了一下,基本评委都给的这个分数,主要评分标准还是以结果为导向的,运行结果有不正确的情况,确实会被扣分的。具体交叉测试哪方面有问题,迟些等评委解答吧

使用道具 举报

回复
论坛徽章:
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
34#
发表于 2011-4-12 21:56 | 只看该作者
原帖由 lugionline 于 2011-4-12 18:20 发表
啊。。。。。。。。

SQL4-27 不就是标准答案最终版的解法吗?怎么分数还这么低啊?

我看你很有当评委的潜质嘛,要不下次拉你入伙?
我特地把27找出来看了一遍,确实和我第三种很像,只是里面有两个自连接journal j1, journal j2和balance b1, balance b2我觉得可以去掉,难道MSSQL没有SUM() OVER()和LEAD,LAG函数?另外几个LEFT JOIN不知道为什么,题目明明有外键。

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
35#
发表于 2011-4-12 22:01 | 只看该作者
我们翻译的27

  1. VAR p_start_date VARCHAR2(8);
  2. VAR p_end_date VARCHAR2(8);
  3. EXEC :p_start_date := '&&p_start_date';
  4. EXEC :p_end_date := '&&p_end_date';
  5. with
  6. journal(usage_id, user_id, service_id, service_date, balance) as
  7. (
  8.         select        usage_id, user_id, service_id,
  9.                         case when start_date < TO_DATE(:p_start_date,'YYYYMMDD') then 1
  10.       else start_date-TO_DATE(:p_start_date,'YYYYMMDD') +1 end service_date,
  11.                         1 balance
  12.         from service_usage
  13.         where        end_date >= TO_DATE(:p_start_date,'YYYYMMDD')
  14.                 and start_date <= TO_DATE(:p_end_date,'YYYYMMDD')
  15.         union
  16.         select        usage_id, user_id, service_id,
  17.                         case when end_date > TO_DATE(:p_end_date,'YYYYMMDD')
  18.                                  then TO_DATE(:p_end_date,'YYYYMMDD')-TO_DATE(:p_start_date,'YYYYMMDD')
  19.         else end_date-TO_DATE(:p_start_date,'YYYYMMDD')+2 end service_date,
  20.                         -1 balance
  21.         from service_usage
  22.         where        end_date >= TO_DATE(:p_start_date,'YYYYMMDD')
  23.                 and start_date <= TO_DATE(:p_end_date,'YYYYMMDD')
  24. )
  25. ,
  26. balance(company_id, service_id, service_date, balance) as
  27. (
  28.         select        service_users.company_id,
  29.                         journal.service_id,
  30.                         journal.service_date,
  31.                         sum(journal.balance) balance
  32.         from
  33.         (
  34.                 select j1.user_id, j1.service_id, j1.service_date,
  35.                         min(j1.balance) balance, sum(j2.balance) accumulate
  36.                 from journal j1, journal j2
  37.                 where        j1.user_id = j2.user_id
  38.                         and j1.service_id = j2.service_id
  39.                         and (j1.service_date > j2.service_date
  40.                          or (j1.service_date = j2.service_date and j1.usage_id >= j2.usage_id))
  41.                 group by j1.user_id, j1.service_id, j1.service_date, j1.usage_id
  42.                 having (min(j1.balance) = 1 and sum(j2.balance) = 1)
  43.                  or (min(j1.balance) = -1 and sum(j2.balance) = 0)
  44.         ) journal left join service_users on journal.user_id = service_users.user_id
  45.         group by service_users.company_id, journal.service_id, journal.service_date
  46. )
  47. ,
  48. fee (company_id, service_id, category_id, balance, days,  rate) as
  49. (
  50.         select
  51.                 company_summary.company_id,
  52.                 company_summary.service_id,
  53.                 service_rates.category_id,
  54.                 company_summary.previous_balance,
  55.                 company_summary.service_date - company_summary.previous_date days,
  56.                 service_rates.rate
  57.         from
  58.         (
  59.                 select b1.company_id, b1.service_id, b1.service_date,
  60.                         b1.balance balance,
  61.                         max(b2.service_date) previous_date,
  62.                         sum(b2.balance) previous_balance
  63.                 from balance b1, balance b2
  64.                 where        b1.company_id = b2.company_id
  65.                         and b1.service_id = b2.service_id
  66.                         and b1.service_date > b2.service_date
  67.                 group by b1.company_id, b1.service_id, b1.service_date, b1.balance
  68.         ) company_summary join service_rates
  69.                 on        company_summary.company_id = service_rates.company_id
  70.                 and company_summary.service_id = service_rates.service_id
  71.                 and company_summary.previous_balance >= service_rates.user_count_min
  72.                 and company_summary.previous_balance <= service_rates.user_count_max
  73.         where        company_summary.previous_date is not null
  74. )
  75. ,
  76. summary(company_id, company_name, service_id, service_name, category_id, fee) as
  77. (
  78.         select        fee.company_id,
  79.                         companies.company_name,
  80.                         fee.service_id,
  81.                         services.service_name,
  82.                         fee.category_id,
  83.                         fee.fee from
  84.         (
  85.                 select        fee.company_id,
  86.                                 fee.service_id,
  87.                                 category_id,
  88.                                 sum(balance * days * rate) fee
  89.                 from fee
  90.                 group by fee.company_id, fee.service_id, category_id
  91.         ) fee
  92.                 left join companies on fee.company_id = companies.company_id
  93.                 left join services on fee.service_id = services.service_id
  94. )
  95. select company_id, company_name,
  96.                         service_id, service_name,
  97.       sum(decode(category_id,1,fee)) fee1,
  98.       sum(decode(category_id,2,fee)) fee2,
  99.       sum(decode(category_id,3,fee)) fee3,
  100.       sum(decode(category_id,4,fee)) fee4,
  101.       sum(fee) feetotal
  102. from summary
  103. group by  company_id, company_name,
  104.                         service_id, service_name     
  105. ;
复制代码

使用道具 举报

回复
论坛徽章:
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
36#
发表于 2011-4-12 22:14 | 只看该作者
关于是否去除同一个人的重复记录,OO在35楼已经回答了:
http://www.itpub.net/thread-1411495-4-1.html

使用道具 举报

回复
论坛徽章:
8
玉兔
日期:2015-11-16 10:18:00铁扇公主
日期:2015-10-27 21:47:42九尾狐狸
日期:2015-12-11 22:31:15
37#
发表于 2011-4-12 22:20 | 只看该作者

回复 #34 newkid 的帖子

那就要多谢谢你了

MSSQL 有SUM Over,但只能按partition后的结果sum,不能做partition同时 order by,所以累计汇总就只能是做自连接,然后找到比当前记录小的所有记录汇总,这就会慢很多。据我所知一句SQL的情况只能这么做,别无它法,但是实际应用,我完全可以弄个临时表,然后用游标遍历记录,虽然游标有点慢,但是比自连接还是快出很多。

left join是为了取得对应的名称吧,我想最后的summary结果会比较少,所以没仔细比较对性能的影响

当评委还是不敢啊,看别人的代码会吐的 ,几位评委这次肯定是严重内伤啊,哈哈

使用道具 举报

回复
论坛徽章:
32
祖国60周年纪念徽章
日期:2009-10-09 08:28:002013年新春福章
日期:2013-02-25 14:51:24迷宫蛋
日期:2013-06-28 11:09:23ITPUB季度 技术新星
日期:2013-07-30 16:04:58优秀写手
日期:2013-12-18 09:29:132014年新春福章
日期:2014-02-18 16:43:09马上有钱
日期:2014-02-18 16:43:09红孩儿
日期:2014-03-04 16:40:38美羊羊
日期:2015-02-16 16:36:28懒羊羊
日期:2015-03-04 14:52:11
38#
发表于 2011-4-12 22:38 | 只看该作者
事先说明各位评委的确是辛苦的,尤其是newkid大侠,呵呵,还有每个语句的点评。
但是我想,如果有题意变更的地方,摆在35楼或者N楼的说明明显不是所有人会看到的,缺乏正式性。
虽然我看了我的解答主要扣分不在这个上面(注释被扣10分,是的,我一点注释也没有):
评审代号:SQL4-17
注释和代码(满分15):        5
思路(满分15):        11.5
性能(满分10):        7.8
完善-基本运行(30分):        28.5
完善-日期交叉测试(30分):        22.8
额外(奇思妙想附加分):      
违规扣分:        0
总计:        75.6

原帖由 newkid 于 2011-4-12 22:14 发表
关于是否去除同一个人的重复记录,OO在35楼已经回答了:
http://www.itpub.net/thread-1411495-4-1.html

使用道具 举报

回复
论坛徽章:
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
39#
发表于 2011-4-12 22:50 | 只看该作者
原帖由 regonly1 于 2011-4-12 22:38 发表
事先说明各位评委的确是辛苦的,尤其是newkid大侠,呵呵,还有每个语句的点评。
但是我想,如果有题意变更的地方,摆在35楼或者N楼的说明明显不是所有人会看到的,缺乏正式性。
虽然我看了我的解答主要扣分不在这个上面(注释被扣10分,是的,我一点注释也没有):
评审代号:SQL4-17
注释和代码(满分15):        5
思路(满分15):        11.5
性能(满分10):        7.8
完善-基本运行(30分):        28.5
完善-日期交叉测试(30分):        22.8
额外(奇思妙想附加分):      
违规扣分:        0
总计:        75.6


谢谢你的包容和理解!
我自己曾经作出了一个和OO相反的回答,后来发现之后赶快纠正,我自己也发PM给两位看到我的回答的选手,并且以为前面的选手都已看到OO的说明。确实,当初应该让贝贝发PM通知每个选手。

使用道具 举报

回复
论坛徽章:
40
授权会员
日期:2009-03-04 17:06:25最佳人气徽章
日期:2013-03-19 17:24:25SQL极客
日期:2013-12-09 14:13:35优秀写手
日期:2013-12-18 09:29:09ITPUB元老
日期:2015-03-04 13:33:34白羊座
日期:2016-03-11 13:49:34乌索普
日期:2017-11-17 11:40:00
40#
发表于 2011-4-12 22:57 | 只看该作者
恶,第四题竟然看错题目了~~

使用道具 举报

回复

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

本版积分规则 发表回复

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