楼主: nyfor

[精华] 支持奥运,趣味挑战用一句SQL实现五角星输出

[复制链接]
论坛徽章:
55
马上加薪
日期:2014-02-19 11:55:142010广州亚运会纪念徽章:排球
日期:2011-04-27 13:27:19SQL大赛参与纪念
日期:2011-04-13 12:08:172011新春纪念徽章
日期:2011-02-18 11:43:332011新春纪念徽章
日期:2011-01-25 15:42:562011新春纪念徽章
日期:2011-01-25 15:42:332011新春纪念徽章
日期:2011-01-25 15:42:152011新春纪念徽章
日期:2011-01-25 15:41:502011新春纪念徽章
日期:2011-01-25 15:41:01生肖徽章2007版:兔
日期:2011-01-20 12:58:49
101#
发表于 2011-1-7 00:20 | 只看该作者

回复 #9 nyfor 的帖子

厉害

使用道具 举报

回复
论坛徽章:
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
102#
发表于 2011-1-7 04:22 | 只看该作者

这个老贴这么多人在顶,就没有人试试新玩法?

把输出部分加工一下:
with a as ( select distinct round(sum(x) over(order by n)) x,
                            round(sum(y) over(order by n)) y
              from (select n,
                           cos(trunc(n / 20) * (1-1/5) * 3.1415926) * 2 x,
                           sin(trunc(n / 20) * (1-1/5) * 3.1415926) y
                      from (select rownum - 1 n from DUAL CONNECT BY rownum <= 20 * 5))
          )
SELECT LPAD(REPLACE(SUM(POWER(10,x-1)),'0',' '),(SELECT MAX(x) FROM a)) AS star
  FROM a
GROUP BY y
ORDER BY y;


STAR
-------------------------------------------------------
                    1
                   1 1
                   1 1
                  1   1
                 11   11
                1       1
                1       1
1 1 1 1 1 1 1 111 1 1 1 111 1 1 1 1 1 1
  11          1           1          11
     11       1           1       11
        1    1             1    1
          11 1             1 11
            11 1         1 11
           1    1 1   1 1    1
           1       1 1       1
          1      1 1 1 1      1
         1    1 1       1 1    1
         1  1               1  1
        11 1                 1 11
        1                       1

美中不足的是缺了一个点,因为ORACLE只能算40位加法。

瘦身版的倒是不缺,就是有些难看:
with a as ( select distinct round(sum(x) over(order by n)) x,
                            round(sum(y) over(order by n)) y
              from (select n,
                           cos(trunc(n / 20) * (1-1/5) * 3.1415926) x,
                           sin(trunc(n / 20) * (1-1/5) * 3.1415926) y
                      from (select rownum - 1 n from DUAL CONNECT BY rownum <= 20 * 5))
          )
SELECT LPAD(REPLACE(SUM(POWER(10,x)),'0',' '),(SELECT MAX(x)+1 FROM a)) AS star
  FROM a
GROUP BY y
ORDER BY y;


STAR
------------------------
          1
          1
         1 1
         1 1
        11 11
        1   1
        1   1
111111111111111111111
11    1     1    11
  11   1     1   11
    1  1     1  1
     11       11
      11     11
      1 11 11 1
     1    1    1
     1   1 1   1
     1 11   11 1
    1 1       1 1
    11         11
    1           1

既然40位不够用,拆成两截再拼回来:

with a as ( select distinct round(sum(x) over(order by n)) x,
                            round(sum(y) over(order by n)) y
              from (select n,
                           cos(trunc(n / 20) * (1-1/5) * 3.1415926) * 2 x,
                           sin(trunc(n / 20) * (1-1/5) * 3.1415926) y
                      from (select rownum - 1 n from DUAL CONNECT BY rownum <= 20 * 5))
          )
SELECT TRANSLATE(LPAD(NVL(SUM(POWER(10,CASE WHEN x>=40 THEN x-40 END)),0),(SELECT MAX(x)-39 FROM a WHERE x>=40))
                 ||LPAD(SUM(POWER(10,CASE WHEN x<40 THEN x END)),40)
                ,'01',' *'
                )
        AS star
  FROM a
GROUP BY y
ORDER BY y;


STAR
---------------------------------------------
                    *
                   * *
                   * *
                  *   *
                 **   **
                *       *
                *       *
* * * * * * * *** * * * *** * * * * * * *
  **          *           *          **
     **       *           *       **
        *    *             *    *
          ** *             * **
            ** *         * **
           *    * *   * *    *
           *       * *       *
          *      * * * *      *
         *    * *       * *    *
         *  *               *  *
        ** *                 * **
        *                       *
        

再来试试11GR2的递归WITH拼接字符串:
with a as (SELECT x,y
                 ,ROW_NUMBER() OVER(PARTITION BY y ORDER BY x) rn
                 ,MAX(x) OVER(PARTITION BY y) maxx
             FROM (select distinct round(sum(x) over(order by n)) x,
                                  round(sum(y) over(order by n)) y
                    from (select n,
                                 cos(trunc(n / 20) * (1-1/5) * 3.1415926) * 2 x,
                                 sin(trunc(n / 20) * (1-1/5) * 3.1415926) y
                            from (select rownum - 1 n from DUAL CONNECT BY rownum <= 20 * 5)
                          )
                   )
          )
,t(rn,x,y,str,maxx) AS (
SELECT 1,x,y,LPAD('*',x+1),maxx FROM a WHERE rn=1
UNION ALL
SELECT a.rn,a.x,t.y,str||RPAD(' ',a.x-t.x-1)||'*',t.maxx
  FROM t,a
WHERE t.rn=a.rn-1 AND t.y=a.y
) CYCLE x,y SET cycle_flag TO 'Y' DEFAULT 'N'
SELECT str FROM t WHERE x=maxx ORDER BY y;


STR
----------------------------------------------------
                    *
                   * *
                   * *
                  *   *
                 **   **
                *       *
                *       *
* * * * * * * *** * * * *** * * * * * * *
  **          *           *          **
     **       *           *       **
        *    *             *    *
          ** *             * **
            ** *         * **
           *    * *   * *    *
           *       * *       *
          *      * * * *      *
         *    * *       * *    *
         *  *               *  *
        ** *                 * **
        *                       *


放大:以10点为单位,设备数为SCALE

VAR SCALE NUMBER;
EXEC :SCALE :=3;

with a as (SELECT x,y
                 ,ROW_NUMBER() OVER(PARTITION BY y ORDER BY x) rn
                 ,MAX(x) OVER(PARTITION BY y) maxx
             FROM (select distinct round(sum(x) over(order by n)) x,
                                  round(sum(y) over(order by n)) y
                    from (select n,
                                 cos(trunc(n / (10*:SCALE)) * (1-1/5) * 3.1415926) * 2 x,
                                 sin(trunc(n / (10*:SCALE)) * (1-1/5) * 3.1415926) y
                            from (select rownum - 1 n from DUAL CONNECT BY rownum <= 10*:SCALE * 5)
                          )
                   )
          )
,t(rn,x,y,str,maxx) AS (
SELECT 1,x,y,LPAD('*',x+1),maxx FROM a WHERE rn=1
UNION ALL
SELECT a.rn,a.x,t.y,str||RPAD(' ',a.x-t.x-1)||'*',t.maxx
  FROM t,a
WHERE t.rn=a.rn-1 AND t.y=a.y
) CYCLE x,y SET cycle_flag TO 'Y' DEFAULT 'N'
SELECT str FROM t WHERE x=maxx ORDER BY y;

STR
----------------------------------------------------------------------
                              *
                             * *
                             * *
                            *   *
                            *   *
                           *     *
                          *       *
                          *       *
                         *         *
                        *           *
                        *           *
* * * * * * * * * * * *** * * * * * *** * * * * * * * * * * *
  **                  **             **                  **
     **              *                 *              **
        *            *                 *            *
          **        *                   *        **
             * *   *                     *   * *
                * **                     ** *
                  **                     **
                  *  * *             * *  *
                 *      * *       * *      *
                *           *   *           *
                *            * *            *
               *          * *   * *          *
               *        *           *        *
              *      * *             * *      *
             *    * *                   * *    *
             * **                           ** *
            **                                 **
           *                                     *

搞了那么多装修,只有核心的坐标计算不敢动

使用道具 举报

回复
论坛徽章:
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
103#
发表于 2011-1-7 04:49 | 只看该作者

利用wmsys.wm_concat的写法其实更简单:
with a as (SELECT x,y
                 ,LAG(x,1,0) OVER(PARTITION BY y ORDER BY x) last_x
             FROM (select distinct round(sum(x) over(order by n)) x,
                                  round(sum(y) over(order by n)) y
                    from (select n,
                                 cos(trunc(n / (10*:SCALE)) * (1-1/5) * 3.1415926) * 2 x,
                                 sin(trunc(n / (10*:SCALE)) * (1-1/5) * 3.1415926) y
                            from (select rownum - 1 n from DUAL CONNECT BY rownum <= 10*:SCALE * 5)
                          )
                   )
          )
SELECT REPLACE(MAX(str),',') STR
  FROM (SELECT y,wmsys.wm_concat(LPAD('*',x-last_x)) OVER(PARTITION BY y ORDER BY x) str
          FROM a
        )
GROUP BY y
ORDER BY y;

STR
----------------------------------------------------------------------
                              *
                             * *
                             * *
                            *   *
                            *   *
                           *     *
                          *       *
                          *       *
                         *         *
                        *           *
                        *           *
* * * * * * * * * * * *** * * * * * *** * * * * * * * * * * *
  **                  **             **                  **
     **              *                 *              **
        *            *                 *            *
          **        *                   *        **
             * *   *                     *   * *
                * **                     ** *
                  **                     **
                  *  * *             * *  *
                 *      * *       * *      *
                *           *   *           *
                *            * *            *
               *          * *   * *          *
               *        *           *        *
              *      * *             * *      *
             *    * *                   * *    *
             * **                           ** *
            **                                 **
           *                                     *


使用道具 举报

回复
论坛徽章:
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
104#
发表于 2011-1-7 04:56 | 只看该作者
再把wmsys.wm_concat变回connect by, 其实就是比楼主少了一个中间步骤:

with a as (SELECT x,y
                 ,LAG(x,1,0) OVER(PARTITION BY y ORDER BY x) last_x
                 ,ROW_NUMBER() OVER(PARTITION BY y ORDER BY x) rn
             FROM (select distinct round(sum(x) over(order by n)) x,
                                  round(sum(y) over(order by n)) y
                    from (select n,
                                 cos(trunc(n / (10*:SCALE)) * (1-1/5) * 3.1415926) * 2 x,
                                 sin(trunc(n / (10*:SCALE)) * (1-1/5) * 3.1415926) y
                            from (select rownum - 1 n from DUAL CONNECT BY rownum <= 10*:SCALE * 5)
                          )
                   )
          )
SELECT REPLACE(MAX(str),',') STR
  FROM (SELECT y,SYS_CONNECT_BY_PATH(LPAD('*',x-last_x),',') str
          FROM a
         START WITH rn=1
        CONNECT BY y=PRIOR y AND rn=PRIOR rn+1
        )
GROUP BY y
ORDER BY y;

使用道具 举报

回复
论坛徽章:
3
ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11
105#
发表于 2011-1-7 15:17 | 只看该作者
两位高人,真牛

使用道具 举报

回复
论坛徽章:
0
106#
发表于 2011-1-7 17:47 | 只看该作者
创造性

使用道具 举报

回复
论坛徽章:
8
CTO参与奖
日期:2009-02-12 11:45:482010新春纪念徽章
日期:2010-03-01 11:04:562010广州亚运会纪念徽章:击剑
日期:2010-11-22 15:29:202011新春纪念徽章
日期:2011-01-04 10:37:10ITPUB十周年纪念徽章
日期:2011-11-01 16:24:51itpub13周年纪念徽章
日期:2014-10-08 15:13:382016猴年福章
日期:2016-02-23 09:58:34秀才
日期:2017-02-22 15:16:26
107#
发表于 2011-1-9 16:31 | 只看该作者
牛~

使用道具 举报

回复
论坛徽章:
68
沸羊羊
日期:2015-03-04 14:43:432015年新春福章
日期:2015-03-06 11:57:31妮可·罗宾
日期:2016-08-13 17:30:51
108#
发表于 2011-6-23 09:30 | 只看该作者
见了高人了!

使用道具 举报

回复
论坛徽章:
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
109#
发表于 2011-6-23 23:26 | 只看该作者
刚刚又玩了一下,发现wmsys.wm_concat在11202下会报错。修改为LISTAGG:

VAR SCALE NUMBER;
EXEC :SCALE :=3;
           
with a as (SELECT x,y
                 ,LAG(x,1,-1) OVER(PARTITION BY y ORDER BY x) last_x
             FROM (SELECT DISTINCT
                          ROUND(SUM(cos(trunc(n / (10*:SCALE)) * (1-1/5) * pi) * 2) OVER(ORDER BY n)) x,
                          ROUND(SUM(sin(trunc(n / (10*:SCALE)) * (1-1/5) * pi)) OVER(ORDER BY n)) y
                     FROM (select rownum - 1 n,asin(1)*2 pi from DUAL CONNECT BY rownum <= 10*:SCALE * 5)
                   )
          )
SELECT LISTAGG(LPAD('*',x-last_x)) WITHIN GROUP(ORDER BY x) str
FROM a
GROUP BY y
ORDER BY y;


或者MODEL:
SELECT MAX(str) FROM (
SELECT *
  FROM (SELECT DISTINCT
               ROUND(SUM(cos(trunc(n / (10*:SCALE)) * (1-1/5) * pi) * 2) OVER(ORDER BY n)) x,
               ROUND(SUM(sin(trunc(n / (10*:SCALE)) * (1-1/5) * pi)) OVER(ORDER BY n)) y
          FROM (select rownum - 1 n,asin(1)*2 pi from DUAL CONNECT BY rownum <= 10*:SCALE * 5)
        )
MODEL
PARTITION BY (y)
DIMENSION BY (ROW_NUMBER() OVER(PARTITION BY y ORDER BY x) rn)
MEASURES (x,CAST('' AS VARCHAR2(100)) str)
RULES (
   str[any] = DECODE(cv(rn),1,LPAD('*',x[cv()]+1),str[cv()-1]||LPAD('*',x[cv()]-x[cv()-1]))
)
)
GROUP BY y
ORDER BY y;

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
110#
 楼主| 发表于 2011-6-24 09:19 | 只看该作者
newkid 好有研究精神啊,佩服佩服

使用道具 举报

回复

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

本版积分规则 发表回复

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