楼主: newkid

连TOM也答不上来的SQL问题,你来试试看!

[复制链接]
论坛徽章:
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
51#
发表于 2010-4-23 02:13 | 只看该作者

回复 #50 newkid 的帖子

多字符也没问题,但需要用replace去做
数据还需要做点特殊处理,并且要用上connect by
麻烦点了,就不折腾了,意思到就是了,呵呵

使用道具 举报

回复
论坛徽章:
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
52#
 楼主| 发表于 2010-4-23 02:56 | 只看该作者
原帖由 lastwinner 于 2010-4-23 02:13 发表
多字符也没问题,但需要用replace去做
数据还需要做点特殊处理,并且要用上connect by
麻烦点了,就不折腾了,意思到就是了,呵呵

REPLACE跟顺序有关,就不能像TRANSLATE那么方便了,你做一下就知道有多麻烦。
还是11GR2好!

使用道具 举报

回复
论坛徽章:
38
授权会员
日期:2005-10-30 17:05:332012新春纪念徽章
日期:2012-02-13 15:12:09现任管理团队成员
日期:2011-11-07 09:46:59ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41ITPUB9周年纪念徽章
日期:2010-10-08 09:31:21版主3段
日期:2012-05-15 15:24:112009新春纪念徽章
日期:2009-01-04 14:52:282010新春纪念徽章
日期:2010-03-01 11:06:202009日食纪念
日期:2009-07-22 09:30:00祖国60周年纪念徽章
日期:2009-10-09 08:28:00
53#
发表于 2010-4-23 03:01 | 只看该作者
原帖由 newkid 于 2010-4-9 22:55 发表
哇!真是八仙过海各显神通,我隆重宣布开发版进入鼎盛时期!

以下是我的几种方法,等会再和各位的对照一下:

VAR s VARCHAR2(200);
EXEC :s := 'A,B,C,D,E,F';

用BITAND的思路:
WITH t AS (
SELECT REGEXP_SUBSTR(:s,'[^,]+',1,ROWNUM) s,COUNT(*) OVER() cnt, ROWNUM rn
  FROM DUAL
CONNECT BY ROWNUM


强烈要求 newkid 同学不要一次性贴出太多种解法。
原因如下:
1。一下子学习不了这么多
2。让我觉得很惭愧

开个玩笑。

使用道具 举报

回复
论坛徽章:
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
54#
 楼主| 发表于 2010-4-23 03:08 | 只看该作者
原帖由 guostong 于 2010-4-23 03:01 发表


强烈要求 newkid 同学不要一次性贴出太多种解法。
原因如下:
1。一下子学习不了这么多
2。让我觉得很惭愧

开个玩笑。

我比你还惭愧,其实我那些方法前面都有人想到了而且更好。

使用道具 举报

回复
论坛徽章:
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
55#
 楼主| 发表于 2010-4-23 03:34 | 只看该作者
学习kingtsi的思路,只求不超过一半的子集然后对调再合并,用于11GR2:

WITH t AS (
SELECT REGEXP_SUBSTR(:s,'[^,]+',1,ROWNUM) s, COUNT(*) OVER() cnt
  FROM DUAL
CONNECT BY ROWNUM<=LENGTH(:s)-LENGTH(REPLACE(:s,','))+1
)
, T2(s,s1,s2,lvl,cnt) AS (
  SELECT s,s s1, REPLACE(','||:s||',',','||s||',',',') as s2, 1 as lvl,cnt
    FROM t
  UNION ALL
  SELECT t.s,t2.s1||','||t.s,REPLACE(','||t2.s2||',',','||t.s||',',',') as s2, t2.lvl+1,t.cnt
    FROM t, T2
   WHERE t2.s<t.s
         AND t2.lvl<TRUNC(t.cnt/2)
)
SELECT s1,TRIM(BOTH ',' FROM s2) FROM t2
UNION ALL
SELECT TRIM(BOTH ',' FROM s2),s1 FROM t2
WHERE lvl<cnt/2
;

这样递归次数少了很多。

使用道具 举报

回复
论坛徽章:
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
56#
发表于 2010-4-23 07:26 | 只看该作者

回复 #55 newkid 的帖子

这个问题用PLSQL怎么解?

使用道具 举报

回复
论坛徽章:
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
57#
 楼主| 发表于 2010-4-23 08:42 | 只看该作者
原帖由 〇〇 于 2010-4-23 07:26 发表
这个问题用PLSQL怎么解?


如果还允许用SQL,就把我#40的写法改成反复JOIN(用临时表或嵌套表加TABLE函数), 如果不用SQL就是一堆循环。你想看哪个?等我明天有空来写一下。

使用道具 举报

回复
论坛徽章:
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
58#
发表于 2010-4-23 09:26 | 只看该作者
原帖由 newkid 于 10-4-23 02:56 发表

REPLACE跟顺序有关,就不能像TRANSLATE那么方便了,你做一下就知道有多麻烦。
还是11GR2好!


你没理解我的意思

,1,2,12,121,33,13,32,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
59#
 楼主| 发表于 2010-4-23 09:33 | 只看该作者
原帖由 lastwinner 于 2010-4-23 09:26 发表


你没理解我的意思

,1,2,12,121,33,13,32,3,


看了上面这个字符串,你能明白我说的了么?
只要元素不重复,就没关系
上班了,晚上有空再看


从你这个串里面去掉2和33怎么做?那不是要两次REPLACE? TRANSLATE只要一次。
可能我一下子理解不了,等你明示。

使用道具 举报

回复
论坛徽章:
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
60#
 楼主| 发表于 2010-4-23 23:00 | 只看该作者
写了个纯PLSQL的版本:

DECLARE
   s VARCHAR2(200) := 'F,B,D,C,E,A';
   TYPE t_str IS TABLE OF VARCHAR2(1000) INDEX BY BINARY_INTEGER;
   ss t_str;
   s1 t_str;
   s2 t_str;
   cnt NUMBER := 0;
   org_s VARCHAR2(200) := s;
   cnt2 NUMBER := 0;
   low NUMBER := 0;
   high NUMBER := 0;
   
   TYPE t_num IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
   id t_num;
   lvl t_num;
   lv_level NUMBER :=1;
BEGIN
   WHILE s IS NOT NULL LOOP
       cnt := cnt+1;
       IF INSTR(s,',')>0 THEN
          ss(cnt) := SUBSTR(s,1,INSTR(s,',')-1);
          s := SUBSTR(s,INSTR(s,',')+1);
       ELSE
          ss(cnt) := s;
          s := '';
       END IF;
       s1(cnt):=ss(cnt);
       id(cnt):=cnt;
       lvl(cnt):=lv_level;
       s2(cnt):=TRIM(BOTH ',' FROM REPLACE(','||org_s||',',','||s1(cnt)||',',','));
   END LOOP;
   cnt2 := cnt;
   low := 1;

   WHILE lv_level<TRUNC(cnt/2) LOOP
      high := cnt2;
      lv_level := lv_level+1;
      FOR i IN low..high LOOP
          FOR j IN id(low)+1..cnt LOOP
              IF id(i)<j THEN
                 cnt2 := cnt2+1;
                 id(cnt2) := j;
                 lvl(cnt2) := lv_level;
                 s1(cnt2):=s1(i)||','||ss(j);
                 s2(cnt2):=TRIM(BOTH ',' FROM REPLACE(','||s2(i)||',',','||ss(j)||',',','));
              END IF;
          END LOOP;
      END LOOP;
      low := high+1;
   END LOOP;

   FOR i IN 1..cnt2 LOOP
       DBMS_OUTPUT.PUT_LINE(s1(i)||'  '||s2(i));
       IF lvl(i)<cnt/2 THEN
          DBMS_OUTPUT.PUT_LINE(s2(i)||'  '||s1(i));
       END IF;
   END LOOP;
END;
/

使用道具 举报

回复

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

本版积分规则 发表回复

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