`
huangningren
  • 浏览: 43496 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

发现一位专门用SQL解各种谜题的高人!

阅读更多

http://oraqa.com/2008/02/01/how-to-solve-the-coin-combinations-puzzle-in-sql/
高人的
http://oraqa.com/author/frank-zhou/


发现一位专门用SQL解各种谜题的高人!


名字叫Frank Zhou, 似乎是中国人:
http://oraqa.com/author/frank-zhou/

最近OO发的几个趣味问题,他早就做过了。他写的SQL很对我的胃口,我准备陆续把一些有趣的问题转贴过来,比如这个:

http://oraqa.com/2008/02/01/how- ... ions-puzzle-in-sql/

Assuming you have enough coins of 1, 5, 10, 25 and 50 cents, how many ways are there to make change for a dollar?

用1分,5分,10分,25分,50分硬币凑成一元,总共有几种组合办法?

我用11GR2的写法:
WITH coins AS (
  SELECT 1 cents FROM DUAL
  UNION ALL SELECT 5 cents FROM DUAL
  UNION ALL SELECT 10 cents FROM DUAL
  UNION ALL SELECT 25 cents FROM DUAL
  UNION ALL SELECT 50 cents FROM DUAL
  )
,t(c1,c5,c10,c25,c50,cents,total_val) AS (
SELECT DECODE(c.cents,1,1,0)
      ,DECODE(c.cents,5,1,0)         
      ,DECODE(c.cents,10,1,0)         
      ,DECODE(c.cents,25,1,0)         
      ,DECODE(c.cents,50,1,0)         
      ,cents
      ,cents
  FROM coins c
UNION ALL
SELECT c1 + DECODE(c.cents,1,1,0)
      ,c5 + DECODE(c.cents,5,1,0)         
      ,c10+ DECODE(c.cents,10,1,0)         
      ,c25+ DECODE(c.cents,25,1,0)         
      ,c50+ DECODE(c.cents,50,1,0)         
      ,c.cents
      ,t.total_val + c.cents
  FROM t, coins c
WHERE t.total_val + c.cents<=100 AND t.cents<=c.cents
)
SELECT * FROM t WHERE total_val=100;

他的写法在11G通不过:
SELECT ltrim(max(str),',') combinations,
       rtrim(ltrim(replace(max(str_num),',','+'),'+'),'+') Sum,
       count(*) over () as counter
FROM
(SELECT sys_connect_by_path(str,', ') str, rownum rn,
        translate(sys_connect_by_path(str_num,','),
                  chr(0)||'ABCDE',chr(0))||',' AS str_num
FROM
(SELECT str_num, str, to_number(substr(str_num,0,length(str_num)-1)) n,
        substr(str_num,length(str_num)) coin_type
  FROM
(SELECT LEVEL||'A' str_num ,   LEVEL||' Penny' AS str
   FROM dual CONNECT BY LEVEL <=100
UNION ALL
SELECT LEVEL*5||'B' str_num,  LEVEL||' Nickel'
   FROM dual CONNECT BY LEVEL*5 <=100
UNION ALL
SELECT LEVEL*10||'C' str_num, LEVEL||' Dime'
   FROM dual CONNECT BY LEVEL*10 <=100
UNION ALL
SELECT LEVEL*25||'D' str_num, LEVEL||' Quarter'
   FROM dual CONNECT BY LEVEL*25 <=100
UNION ALL
SELECT LEVEL*50||'E' str_num, LEVEL||' Half D$'
   FROM dual CONNECT BY LEVEL*50<=100
)
)
WHERE
CASE LEVEL
WHEN  1 THEN CASE WHEN n = 100 THEN 1 END
WHEN  2 THEN CASE WHEN n + PRIOR  n =100 THEN 1 END
WHEN  3 THEN CASE WHEN CONNECT_BY_ROOT n + PRIOR n + n =100 THEN 1 END
ELSE  1 END =1
CONNECT BY PRIOR coin_type < coin_type
AND
CASE LEVEL
WHEN 2 THEN CASE WHEN n + PRIOR  n <=100 THEN 1 END
WHEN 3 THEN CASE WHEN CONNECT_BY_ROOT n + PRIOR n + n <=100 THEN 1 END
WHEN 4 THEN CASE WHEN CONNECT_BY_ROOT n + PRIOR n + n <96   THEN 1 END
WHEN 5 THEN CASE WHEN CONNECT_BY_ROOT n + PRIOR n + n <=85  THEN 1 END
ELSE 1 END =1
)
CONNECT BY PRIOR rn = rn
AND INSTR(str_num,',', 1,LEVEL+1) > 0
AND PRIOR dbms_random.string('p',10) IS NOT NULL
GROUP BY rn
HAVING SUM(TO_NUMBER(SUBSTR(str_num,
           INSTR(str_num,',', 1, LEVEL) + 1,
           INSTR(str_num,',', 1, LEVEL+1) -
           INSTR(str_num,',', 1, LEVEL) -1))) = 100 ;

WHEN 3 THEN CASE WHEN CONNECT_BY_ROOT n + PRIOR n + n <=100 THEN 1 END
                      *
ERROR at line 38:
ORA-30007: CONNECT BY ROOT operator is not supported in the START WITH or in the CONNECT BY condition

印象中只有某个版本允许在CONNECT BY条件中使用CONNECT_BY_ROOT。
发现一位专门用SQL解各种谜题的高人!
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics