可能涉及递归算法的SQL难题,求高手当头棒喝:嘿!你这呆子!!

wenlin56 2012-10-24 11:59:35
Table结构入下图:


题目是:
用一个sql语句统计出各个根区域(隶属地域为-1的即为根区域)的用户累计上网时长。


例如:
重庆的“隶属区域”为-1,所以它是根区域。有两个区(九龙坡和渝中区)隶属于它,而其中的九龙坡下面又有“石桥铺”隶属于它。
重庆、九龙坡、渝中区和石桥铺这些地区,分别有部分用户,这些用户的上网时长的总和,就是“重庆”的上网时长。

最后的结果:
北京 6500
重庆 900

数据库环境:
oracle

我思考了很久,由于最初没有考虑到地域的关系可能是三级(甚至更多级,只简单的查询所有用户,并对“隶属地域”分组(group by 隶属区域)。这显然是错误的。
如果地域为多级,sql里面应该要包含一个递归的算法?从根区域,遍历所有子区域,得出总和。
但是本人水平太菜,愣是没憋出来这条sql。

这里寻求同行一同讨论。

谢谢大家~~ 哈哈


...全文
277 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
fw0124 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]
引用 3 楼 的回复:

一大牛哥们的答案,分享~~

地域表:A
用户表:B
时长表:C
select D.名称,sum(D.上网时长)(select A.名称,C.上网时长 from C left join B on C.用户编号=B.编号 left join A
on B.所属地区编号=A.编号) D group by D.上网时长

上面笔误,应是这样
select ……
[/Quote]
得出来的是这个结果???
名称 SUM(D.上网时长)
------ ----------------------
九龙坡 4500
重庆 400
渝中区 2000
石桥铺 500
wenlin56 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

引用 3 楼 的回复:

一大牛哥们的答案,分享~~

地域表:A
用户表:B
时长表:C
select D.名称,sum(D.上网时长)(select A.名称,C.上网时长 from C left join B on C.用户编号=B.编号 left join A
on B.所属地区编号=A.编号) D group by D.上网时长

上面笔误,应是这样
selec……
[/Quote]
有错误,因为这个会查询出所有地点。
而最后只能得出
北京 6500
重庆 900

其它二三级地域,要归到根区域去...
fw0124 2012-10-24
  • 打赏
  • 举报
回复
先用connect by得到父子结构,并用connect_by_root关键字找到每个地域的根地域,
然后和上网时长,用户表关联得到每个上网时长所属的根地域,
然后对根地域做个group by就得到结果了。
下面最后出来的是根地域编号,如果要得到根地域名称,你在外面再套层查询就ok.

select t2.根地域编号, sum(t1.上网时长) from
(select 上网时长.上网时长, 地域表.编号 地域编号 from 上网时长
left join 用户表 on 上网时长.用户编号=用户表.编号
left join 地域表 on 用户表.所属地区编号=地域表.编号) t1 join
(select 地域表.编号 地域编号, 地域表.名称 地域名称, connect_by_root 地域表.编号 根地域编号 from 地域表
start with 隶属地域 = -1 connect by prior 编号=隶属地域) t2 on t1.地域编号=t2.地域编号
group by t2.根地域编号;
wenlin56 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

一大牛哥们的答案,分享~~

地域表:A
用户表:B
时长表:C
select D.名称,sum(D.上网时长)(select A.名称,C.上网时长 from C left join B on C.用户编号=B.编号 left join A
on B.所属地区编号=A.编号) D group by D.上网时长
[/Quote]
上面笔误,应是这样
select
D.名称,sum(D.上网时长)
from
(select
A.名称,C.上网时长
from C left join B on C.用户编号=B.编号
left join A on B.所属地区编号=A.编号
) D
group by D.名称
wenlin56 2012-10-24
  • 打赏
  • 举报
回复
一大牛哥们的答案,分享~~

地域表:A
用户表:B
时长表:C
select D.名称,sum(D.上网时长)(select A.名称,C.上网时长 from C left join B on C.用户编号=B.编号 left join A
on B.所属地区编号=A.编号) D group by D.上网时长
wenlin56 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

不需要递归,用connect by就可以了。
[/Quote]
没用过,我去查查。能具体说下方案么...
fw0124 2012-10-24
  • 打赏
  • 举报
回复
不需要递归,用connect by就可以了。
forgetsam 2012-10-24
  • 打赏
  • 举报
回复
数据库有什么递归,无限join就可以。
不定次数的join 用connect by 语法。
chen254810107 2012-10-24
  • 打赏
  • 举报
回复
顶了 , 学习了, 支持五楼
wenlin56 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

with t as (
select c.time,b.areaid from area a,suser b ,nettime c
where a.id=b.areaid and b.id=c.userid)
select id,name,(select sum(time) from t where
t where t.id in (select id from area b st……
[/Quote]

正在试,这种写法没见过,学习了!
wenlin56 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

先用connect by得到父子结构,并用connect_by_root关键字找到每个地域的根地域,
然后和上网时长,用户表关联得到每个上网时长所属的根地域,
然后对根地域做个group by就得到结果了。
下面最后出来的是根地域编号,如果要得到根地域名称,你在外面再套层查询就ok.

SQL code
select t2.根地域编号, sum(t1.上网时长) from
(se……
[/Quote]
谢谢! 经测试正确。
朋友给出了另一个方案

select E.名称,sum(E.上网时长)
from
(select D.名称,C.上网时长 from C left join B on C.用户编号=B.编号 left join
(select A.编号,connect_by_root(A.名称) 名称 from A start with A.隶属地域 = -1 connect by prior A.编号=A.隶属地域) D
on B.所属地区编号=D.编号) E
group by E.名称
book523 2012-10-24
  • 打赏
  • 举报
回复
区域表:area
用户表:suser
上网时间:nettime
其他字段对应应该很容易能看出来,sql没有测试,按这个思路肯定能出正确结果,如有问题及时反馈。
book523 2012-10-24
  • 打赏
  • 举报
回复
with t as (
select c.time,b.areaid from area a,suser b ,nettime c
where a.id=b.areaid and b.id=c.userid)
select id,name,(select sum(time) from t where
t where t.id in (select id from area b start with b.id=a.id
prior b.sjid=b.id )) counttime
from area a where a.sjid=-1
book523 2012-10-24
  • 打赏
  • 举报
回复
简单的sql,马上给你解答。

17,140

社区成员

发帖
与我相关
我的任务
社区描述
Oracle开发相关技术讨论
社区管理员
  • 开发
  • Lucifer三思而后行
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧