2009-10-27 107 views
0

使用Oracle 10.2.0。Oracle - 多级自然排序行

我有一个由行号,缩进级别和文本组成的表格。我需要编写一个例程来'自然'对缩进级别内的文本进行排序[这是缩进级别较低的子节点]。我在分析例程方面经验有限,并且通过/之前进行连接,但是从我在这里和其他地方阅读的内容看来,似乎可以用它们来帮助我的事业,但我无法弄清楚。

CREATE TABLE t (ord NUMBER(5), indent NUMBER(3), text VARCHAR2(254)); 

INSERT INTO t (ord, indent, text) VALUES (10, 0, 'A'); 
INSERT INTO t (ord, indent, text) VALUES (20, 1, 'B'); 
INSERT INTO t (ord, indent, text) VALUES (30, 1, 'C'); 
INSERT INTO t (ord, indent, text) VALUES (40, 2, 'D'); 
INSERT INTO t (ord, indent, text) VALUES (50, 2, 'Z'); 
INSERT INTO t (ord, indent, text) VALUES (60, 2, 'E'); 
INSERT INTO t (ord, indent, text) VALUES (70, 1, 'F'); 
INSERT INTO t (ord, indent, text) VALUES (80, 2, 'H'); 
INSERT INTO t (ord, indent, text) VALUES (90, 2, 'G'); 
INSERT INTO t (ord, indent, text) VALUES (100, 3, 'J'); 
INSERT INTO t (ord, indent, text) VALUES (110, 3, 'H'); 

此:

SELECT ord, indent, LPAD(' ', indent, ' ') || text txt FROM t; 

...的回报:选择

ORD  INDENT  TXT 
---------- ---------- ---------------------------------------------- 
    10   0  A 
    20   1  B 
    30   1  C 
    40   2  D 
    50   2  Z 
    60   2  E 
    70   1  F 
    80   2  H 
    90   2  G 
    100   3   J 
    110   3   H 

11行。

在我为您定义的情况下,我需要我的程序设置ORD 60 = 50和ORD 50 = 60它们翻转],因为E是后d和Z之前
同样的,ORD 80和90 [90使100和110与它,因为它们属于它],100和110的最终输出应为:

ORD  INDENT TXT 

10   0 A 
    20   1 B 
    30   1 C 
    40   2 D 
    50   2 E 
    60   2 Z 
    70   1 F 
    80   2 G 
    90   3 H 
    100   3 J 
    110   2 H 

其结果是,每个缩进级别按字母顺序排序,在其缩进级别内,在缩进级别内。

+0

听起来像是给我的家庭作业。 – Gandalf 2009-10-27 20:29:36

+0

似乎很难做家庭作业,但谁知道? – Lucero 2009-10-27 20:33:49

+0

它不是一项家庭作业。我已经极大地简化了表格和数据,专注于答案,而不是无关的数据。 – user55904 2009-10-27 20:48:23

回答

1

这是我的工作。不知道它可能在更大的集合上有多高效。对我而言,困难的部分是完全基于缩进和原始顺序来确定给定行的“父”。

WITH 
    a AS (
     SELECT 
      t.*, 
      (SELECT MAX(ord) 
       FROM t t2 
       WHERE t2.ord < t.ord AND t2.indent = t.indent-1 
      ) AS parent_ord 
     FROM 
      t 
    ) 
SELECT 
    ROWNUM*10 AS ord, 
    indent, 
    rpad(' ', LEVEL-1, ' ') || text 
FROM 
    a 
CONNECT BY 
    PRIOR ord = parent_ord 
START WITH 
    parent_ord IS NULL 
ORDER SIBLINGS BY 
    text 
+0

嘿嘿......几乎同时发布。我必须承认,你找到父母的方式更小,我很难... – Lucero 2009-10-27 23:01:21

+0

谢谢!我找不到我的父亲!神奇的解决方案! – user55904 2009-10-28 12:57:13

0

好的,在这里你去。数据结构中的难点在于父对象不是(明确)已知的,因此查询的第一部分根据规则只会识别父对象(对于每个节点,它将获得所有子节点一级深度,停止只要标识小于或等于开始节点)。

其余的很容易,基本上只是一些递归与连接,以获得您想要他们的顺序(动态重新编号他们的项目)的项目。

WITH OrdWithParentInfo AS 
(SELECT ID, 
     INDENT, 
     TEXT, 
     MIN(ParentID) ParentID 
    FROM (SELECT O.*, 
       CASE 
        WHEN (CONNECT_BY_ROOT ID = ID) THEN 
        NULL 
        ELSE 
        CONNECT_BY_ROOT ID 
       END ParentID 
      FROM (SELECT ROWNUM ID, 
         INDENT, 
         TEXT 
        FROM T 
        ORDER BY ORD) O 
      WHERE (INDENT = CONNECT_BY_ROOT INDENT + 1) 
       OR (CONNECT_BY_ROOT ID = ID) 
      CONNECT BY ((ID = PRIOR ID + 1) AND (INDENT > CONNECT_BY_ROOT INDENT))) 
    GROUP BY ID, 
      INDENT, 
      TEXT) 
SELECT ROWNUM * 10 ORD, O.INDENT, O.TEXT 
FROM OrdWithParentInfo O 
START WITH O.ParentID IS NULL 
CONNECT BY O.ParentID = PRIOR ID 
ORDER SIBLINGS BY O.Text; 
+0

伟大的思想想象:-) – kurosch 2009-10-27 23:01:44

+0

我想是的(尽管我没有看到自己是“伟大的心灵”))。反正很有趣。 – Lucero 2009-10-27 23:06:30