Domanda

Uso di Oracle 10.2.0.

Ho una tabella che consiste in un numero di riga, un livello di rientro e testo. Devo scrivere una routine per ordinare in modo "naturale" il testo all'interno di un livello di rientro [che è figlio di un livello di rientro inferiore]. Ho una limitata esperienza con le routine analitiche e mi connetto da / precedente, ma da quello che ho letto qui e altrove, sembra che potrebbero essere utilizzate per aiutare la mia causa, ma non riesco a capire come.

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');  

Questa:

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

... rendimenti:

   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 righe selezionate.

Nel caso che ho definito per te, ho bisogno della mia routine di impostare ORD 60 = 50 e ORD 50 = 60 [capovolgili] perché E è dopo D e prima di Z.
Lo stesso vale per ORD 80 e 90 [con 90 che portano 100 e 110 perché appartengono ad esso], 100 e 110. L'output finale dovrebbe essere:

   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  

Il risultato è che ogni livello di rientro è ordinato alfabeticamente, all'interno del livello di rientro, all'interno del livello di rientro principale.

È stato utile?

Soluzione

Ecco cosa devo lavorare. Non ho idea di quanto possa essere efficiente su set più grandi. La parte difficile per me era identificare il "genitore" per una determinata riga basata esclusivamente sul rientro e sull'ordine originale.

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

Altri suggerimenti

Okay, eccoti. La parte difficile nella struttura dei dati è che il genitore non è (esplicitamente) conosciuto, quindi la prima parte della query non fa altro che identificare il genitore secondo le regole (per ogni nodo, ottiene tutti i nodi secondari a un livello di profondità, arrestandosi non appena l'identificazione è più piccola o uguale al nodo iniziale).

Il resto è facile, in pratica solo qualche ricorsione con connect by per ottenere gli oggetti nell'ordine desiderato (rinumerandoli dinamicamente).

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top