
(CSDN博主:写代码也要符合基本法)

(图片自网络)
SQL> SELECT loc_code, loc_name, parent_code FROM demo_locations2 /LOC_CODE LOC_NAME PARENT_CODE---------- ---------- -----------100000 山东 0200000 广东 0110000 菏泽 100000120000 青岛 100000210000 佛山 200000220000 深圳 200000111000 曹县 110000112000 单县 110000113000 巨野 1100009 rows selected

说起来题目倒是简单,要求的展示结果也没有难以理解的地方。但越是这种看起来简单的问题,实现起来却弯弯绕绕的越多
SQL> SELECT t1.loc_name loc1, t2.loc_name loc2, t3.loc_name loc32 FROM demo_locations t1, demo_locations t2, demo_locations t33 WHERE t1.loc_code = t2.parent_code(+)4 AND t2.loc_code = t3.parent_code(+)5 AND t1.parent_code = '0'6 /LOC1 LOC2 LOC3---------- ---------- ----------山东 菏泽 曹县山东 菏泽 单县山东 菏泽 巨野山东 青岛广东 佛山广东 深圳6 rows selected
虽然和最终结果还有差距,但已粗具规模,至少三列的层次已经尽数展现了

这当然是外连接本来的作用决定的:主表中的行即便关联不出外连接表里的数据,也要选择到结果集中。其隐含的意思是,关联不出的行都显示了,更别说能关联出来数据的行了,肯定是携手外连接表的数据一起显示了

说到这里,一定会有老爷说:做题就做题,你嘚嘚外连接干什么?你这就是在凑字数
GROUP BY t1.loc_name, ROLLUP(t2.loc_name, t3.loc_name)
使用如上的分组规则,就能在不置空省列的前提下,多实现两种情形的分组:市列 + 置空的县列,以及置空的市列和县列

问题看起来是只有省和市的行重复出现了,原因也很好想到:佛山、深圳、青岛三市的行在原结果中就有,如今出现的两行分别是本来 LOC3 就为空的行(外连接所得)跟置空 LOC3 的行(分组所得)
SQL> SELECT t1.loc_name loc1, t2.loc_name loc2, t3.loc_name loc32 FROM demo_locations t1, demo_locations t2, demo_locations t33 WHERE t1.parent_code = '0'4 AND t1.loc_code = t2.parent_code(+)5 AND t2.loc_code = t3.parent_code(+)6 GROUP BY t1.loc_name, ROLLUP(t2.loc_name, t3.loc_name)7 HAVING grouping(t3.loc_name) = 1 OR t3.loc_name IS NOT NULL8 ORDER BY loc1, loc2 NULLS FIRST, loc3 NULLS FIRST9 /LOC1 LOC2 LOC3---------- ---------- ----------广东广东 佛山广东 深圳山东山东 菏泽山东 菏泽 曹县山东 菏泽 单县山东 菏泽 巨野山东 青岛9 rows selected
效果还不错

查询路径?SYS_CONNECT_BY_PATH 一听:我四干介个的啊 → 传送门
SQL> WITH conn AS2 (SELECT sys_connect_by_path(loc_name, '.') p3 FROM demo_locations4 CONNECT BY PRIOR loc_code = parent_code5 START WITH parent_code = '0')6 SELECT regexp_substr(p, '[^\.]+', 1, 1) loc17 ,regexp_substr(p, '[^\.]+', 1, 2) loc28 ,regexp_substr(p, '[^\.]+', 1, 3) loc39 FROM conn10 /LOC1 LOC2 LOC3---------- ---------- ----------山东山东 菏泽山东 菏泽 曹县山东 菏泽 单县山东 菏泽 巨野山东 青岛广东广东 佛山广东 深圳9 rows selected

SQL> WITH conn(lv, loc_code, loc1, loc2, loc3) AS2 (SELECT 1 lv, loc_code, loc_name loc1, NULL loc2, NULL loc33 FROM demo_locations4 WHERE parent_code = '0'5 UNION ALL6 SELECT c.lv + 1 lv7 ,l.loc_code8 ,c.loc19 ,decode(c.lv + 1, 2, l.loc_name, c.loc2) loc210 ,decode(c.lv + 1, 3, l.loc_name, c.loc3) loc311 FROM conn c, demo_locations l12 WHERE c.loc_code = l.parent_code)13 SELECT loc1, loc2, loc3 FROM conn ORDER BY loc_code14 /LOC1 LOC2 LOC3---------- ---------- ----------山东山东 菏泽山东 菏泽 曹县山东 菏泽 单县山东 菏泽 巨野山东 青岛广东广东 佛山广东 深圳9 rows selected

SQL> SELECT t1.loc_name loc12 ,t2.loc_name loc23 ,t3.loc_name loc34 ,t4.loc_name loc45 FROM demo_locations t16 ,demo_locations t27 ,demo_locations t38 ,demo_locations t49 WHERE t1.parent_code = '0'10 AND t1.loc_code = t2.parent_code(+)11 AND t2.loc_code = t3.parent_code(+)12 AND t3.loc_code = t4.parent_code(+)13 GROUP BY t1.loc_name, ROLLUP(t2.loc_name, t3.loc_name, t4.loc_name)14 HAVING grouping_id(t3.loc_name, t4.loc_name) = 3 OR15 grouping_id(t3.loc_name, t4.loc_name) = 1 AND t3.loc_name IS NOT NULL OR16 t4.loc_name IS NOT NULL17 ORDER BY loc1, loc2 NULLS FIRST, loc3 NULLS FIRST, loc4 NULLS FIRST18 /LOC1 LOC2 LOC3 LOC4---------- ---------- ---------- ----------广东广东 佛山广东 深圳山东山东 菏泽山东 菏泽 曹县山东 菏泽 曹县 牛逼山东 菏泽 单县山东 菏泽 巨野山东 青岛10 rows selectedSQL> WITH conn AS2 (SELECT sys_connect_by_path(loc_name, '.') p3 FROM demo_locations4 CONNECT BY PRIOR loc_code = parent_code5 START WITH parent_code = '0')6 SELECT regexp_substr(p, '[^\.]+', 1, 1) loc17 ,regexp_substr(p, '[^\.]+', 1, 2) loc28 ,regexp_substr(p, '[^\.]+', 1, 3) loc39 ,regexp_substr(p, '[^\.]+', 1, 4) loc410 FROM conn11 /LOC1 LOC2 LOC3 LOC4---------- ---------- ---------- ----------山东山东 菏泽山东 菏泽 曹县山东 菏泽 曹县 牛逼山东 菏泽 单县山东 菏泽 巨野山东 青岛广东广东 佛山广东 深圳10 rows selectedSQL> WITH conn(lv, loc_code, loc1, loc2, loc3, loc4) AS2 (SELECT 1 lv, loc_code, loc_name loc1, NULL loc2, NULL loc3, NULL loc43 FROM demo_locations4 WHERE parent_code = '0'5 UNION ALL6 SELECT c.lv + 1 lv7 ,l.loc_code8 ,c.loc19 ,decode(c.lv + 1, 2, l.loc_name, c.loc2) loc210 ,decode(c.lv + 1, 3, l.loc_name, c.loc3) loc311 ,decode(c.lv + 1, 4, l.loc_name, c.loc4) loc412 FROM conn c, demo_locations l13 WHERE c.loc_code = l.parent_code)14 SELECT loc1, loc2, loc3, loc4 FROM conn ORDER BY loc_code15 /LOC1 LOC2 LOC3 LOC4---------- ---------- ---------- ----------山东山东 菏泽山东 菏泽 曹县山东 菏泽 曹县 牛逼山东 菏泽 单县山东 菏泽 巨野山东 青岛广东广东 佛山广东 深圳10 rows selected
另外,今天方案一的 SQL 小刘写的其实是有 bug 的(提示:出现光杆省的情况),给大家留作思考的空间 


文章转载自SQL干货分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




