楼主: water1108

[精华] 求一SQL算法【找团伙】

[复制链接]
论坛徽章:
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
11#
发表于 2009-11-4 14:38 | 只看该作者
原帖由 chen222246lei 于 2009-11-4 13:49 发表
WITH TEMP AS
(
SELECT 'a1'  COL_A,'a4' COL_B FROM DUAL UNION
SELECT 'a1'  COL_A,'a3' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a2' COL_B FROM DUAL UNION
SELECT 'a3'  COL_A,'a6' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a1' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a8' COL_B FROM DUAL UNION
SELECT 'a10' COL_A,'a5' COL_B FROM DUAL UNION
SELECT 'a5'  COL_A,'a9' COL_B FROM DUAL
)
SELECT MAX(TEXT1) TEXT FROM
(SELECT WMSYS.WM_CONCAT(TEXT) OVER(PARTITION BY GROP ORDER BY RN1) TEXT1,T.* FROM
  (SELECT TEXT,RN1,SUM(GROP) OVER(ORDER BY RN1) GROP,ROW_NUMBER() OVER(PARTITION BY TEXT ORDER BY RN1) RN2 FROM
    (SELECT COL_B TEXT,ROWNUM RN1,DECODE(LEVEL,1,1,0) GROP FROM
      (SELECT NULL COL_A,COL_A COL_B FROM TEMP GROUP BY COL_A
       UNION
       SELECT * FROM TEMP
      ) CONNECT BY NOCYCLE COL_A = PRIOR COL_B START WITH COL_A IS NULL
    ) T ORDER BY RN1
  ) T WHERE RN2 = 1
  ) GROUP BY GROP

1        a1,a3,a6,a4,a2,a8
2        a10,a5,a9

  
我也來一個:
with test as (
select 'a1' l,'a4' r from dual union all
select 'a1','a3' from dual union all
select 'a4','a2' from dual union all
select 'a3','a6' from dual union all
select 'a4','a1' from dual union all
select 'a4','a8' from dual union all
select 'a10','a5' from dual union all
select 'a5','a9' from dual)
select wm_concat(l)
  from (select l, sum(dbms_utility.get_hash_value(r, 100000000, 10000)) sm /* 假定值最多有10000個 */
          from (select distinct connect_by_root l l, r
                  from (select l, r
                          from test
                        union
                        select r, l from test)
                connect by nocycle l = prior r)
         group by l)
group by sm;

WM_CONCAT(L)
--------------------------------------------------------------------------------
a10,a9,a5
a1,a8,a6,a2,a4,a3

[ 本帖最后由 nyfor 于 2009-11-4 15:01 编辑 ]

使用道具 举报

回复
论坛徽章:
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
12#
发表于 2009-11-4 14:45 | 只看该作者
我的 dbms_utility.get_hash_value(r, 1, 100000) 這個使用似乎有點問題. 會導致結果不正確.
修改一下, 假設值最多有10000個不同的值, 則改成:
dbms_utility.get_hash_value(r, 100000000, 10000) 這可能就對了.

使用道具 举报

回复
论坛徽章:
10
生肖徽章2007版:蛇
日期:2008-10-16 15:37:262011新春纪念徽章
日期:2011-02-18 11:43:35祖国60周年纪念徽章
日期:2009-10-09 08:28:00生肖徽章2007版:蛇
日期:2009-04-23 10:20:26生肖徽章2007版:鸡
日期:2009-03-10 21:16:44数据库板块每日发贴之星
日期:2009-01-08 01:01:022009新春纪念徽章
日期:2009-01-04 14:52:28生肖徽章2007版:蛇
日期:2008-10-27 16:26:10奥运会纪念徽章:举重
日期:2008-10-24 13:16:31一汽
日期:2013-10-28 20:43:00
13#
发表于 2009-11-4 14:54 | 只看该作者
MARK下

使用道具 举报

回复
论坛徽章:
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
14#
发表于 2009-11-4 15:34 | 只看该作者

回复 #11 nyfor 的帖子

强手如云啊

使用道具 举报

回复
论坛徽章:
1
优秀写手
日期:2014-11-05 06:00:03
15#
 楼主| 发表于 2009-11-4 17:43 | 只看该作者
真是高手如云呀,小弟在此深表感谢,以后可能还有问题请教各位高手,希望不吝赐教!

使用道具 举报

回复
论坛徽章:
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
16#
发表于 2009-11-4 23:37 | 只看该作者
原帖由 chen222246lei 于 2009-11-4 13:49 发表
WITH TEMP AS
(
SELECT 'a1'  COL_A,'a4' COL_B FROM DUAL UNION
SELECT 'a1'  COL_A,'a3' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a2' COL_B FROM DUAL UNION
SELECT 'a3'  COL_A,'a6' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a1' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a8' COL_B FROM DUAL UNION
SELECT 'a10' COL_A,'a5' COL_B FROM DUAL UNION
SELECT 'a5'  COL_A,'a9' COL_B FROM DUAL
)
SELECT MAX(TEXT1) TEXT FROM
(SELECT WMSYS.WM_CONCAT(TEXT) OVER(PARTITION BY GROP ORDER BY RN1) TEXT1,T.* FROM
  (SELECT TEXT,RN1,SUM(GROP) OVER(ORDER BY RN1) GROP,ROW_NUMBER() OVER(PARTITION BY TEXT ORDER BY RN1) RN2 FROM
    (SELECT COL_B TEXT,ROWNUM RN1,DECODE(LEVEL,1,1,0) GROP FROM
      (SELECT NULL COL_A,COL_A COL_B FROM TEMP GROUP BY COL_A
       UNION
       SELECT * FROM TEMP
      ) CONNECT BY NOCYCLE COL_A = PRIOR COL_B START WITH COL_A IS NULL
    ) T ORDER BY RN1
  ) T WHERE RN2 = 1
  ) GROUP BY GROP

1        a1,a3,a6,a4,a2,a8
2        a10,a5,a9


这里面有个BUG, 如果加一个SELECT 'a11'  COL_A,'a8' COL_B FROM DUAL UNION...
则A11并不到结果里面。
把最里头的查询改为:
SELECT NULL COL_A,COL_A COL_B FROM (SELECT COL_A,COL_B FROM TEMP UNION ALL SELECT COL_B,COL_A FROM TEMP) GROUP BY COL_A
       UNION
       SELECT * FROM TEMP
       UNION SELECT COL_B,COL_A FROM TEMP
似乎可以解决了,但看起来还是怪怪的,因为有一个ROWNUM没有经过排序……等会有空再看看。

使用道具 举报

回复
论坛徽章:
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
17#
发表于 2009-11-4 23:43 | 只看该作者
原帖由 nyfor 于 2009-11-4 14:38 发表

  
我也來一個:
with test as (
select 'a1' l,'a4' r from dual union all
select 'a1','a3' from dual union all
select 'a4','a2' from dual union all
select 'a3','a6' from dual union all
select 'a4','a1' from dual union all
select 'a4','a8' from dual union all
select 'a10','a5' from dual union all
select 'a5','a9' from dual)
select wm_concat(l)
  from (select l, sum(dbms_utility.get_hash_value(r, 100000000, 10000)) sm /* 假定值最多有10000個 */
          from (select distinct connect_by_root l l, r
                  from (select l, r
                          from test
                        union
                        select r, l from test)
                connect by nocycle l = prior r)
         group by l)
group by sm;

WM_CONCAT(L)
--------------------------------------------------------------------------------
a10,a9,a5
a1,a8,a6,a2,a4,a3

你这个比较好懂,但总有点不踏实……
先不说HASH本身碰撞的可能,把不同的HASH值求和,则碰撞的机会大大增加了。除非你事先为每个元素分配二进制的一位?但是这样表达的个数就太少了。

使用道具 举报

回复
论坛徽章:
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
18#
发表于 2009-11-5 03:31 | 只看该作者
chen222246lei的思路经简化、改写:
WITH TEMP AS
(
SELECT 'a1'  COL_A,'a4' COL_B FROM DUAL UNION
SELECT 'a1'  COL_A,'a3' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a2' COL_B FROM DUAL UNION
SELECT 'a3'  COL_A,'a6' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a1' COL_B FROM DUAL UNION
SELECT 'a4'  COL_A,'a8' COL_B FROM DUAL UNION
SELECT 'a10' COL_A,'a5' COL_B FROM DUAL UNION
SELECT 'a5'  COL_A,'a9' COL_B FROM DUAL
)
SELECT WMSYS.WM_CONCAT(TEXT) FROM
  (SELECT TEXT,RT,ROW_NUMBER() OVER(PARTITION BY TEXT ORDER BY RN1) RN2 FROM
    (SELECT COL_B TEXT,ROWNUM RN1,CONNECT_BY_ROOT(COL_A) RT --- 这个ROOT的作用和原来的GROP其实是一个道理
       FROM
      (SELECT * FROM TEMP
       UNION SELECT COL_B,COL_A FROM TEMP  --- 加上双向遍历
      ) CONNECT BY NOCYCLE COL_A = PRIOR COL_B
    ) T
  ) T WHERE RN2 = 1
GROUP BY RT;
这个方法依赖于CONNECT BY的输出顺序。


nyfor的HASH方法不是很保险,用wm_concat代替后:
SELECT DISTINCT MAX(res)
  FROM (select l, wmsys.wm_concat(r) OVER(PARTITION BY l ORDER BY r) res  ---GROUP BY中的wm_concat不能排序所以先用分析函数。如果用11GR2的LISTAGG的within group (ORDER BY...)则可以省略这一步
          from (select distinct connect_by_root l l, r
                  from (select l, r
                          from test
                        union
                        select r, l from test)
                connect by nocycle l = prior r
                )
       )
GROUP BY l;

CONNECT BY的方法有不必要的遍历,PLSQL的方法必须反复扫描表,各有优缺点,但数据量大了都吃不消!我记得以前回过一个类似的帖子, 找不到了。

使用道具 举报

回复
论坛徽章:
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
19#
发表于 2009-11-5 08:20 | 只看该作者
nice

使用道具 举报

回复
论坛徽章:
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
20#
发表于 2009-11-5 09:35 | 只看该作者

回复 #18 newkid 的帖子

沒錯,我的Hash法不保險, 昨晚洗澡的時候想到了其中的漏洞.
還是 Newkid 厲害, 一眼就看出問題了.

使用道具 举报

回复

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

本版积分规则 发表回复

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