2012-11-24 9 views
11

L'utilizzo di CONNECT BY LEVEL sembra restituire troppe righe quando eseguito su un tavolo. Qual è la logica dietro ciò che sta accadendo?Perché CONNECT BY LEVEL su un tavolo restituisce righe aggiuntive?

Assumendo la seguente tabella:

create table a (id number); 

insert into a values (1); 
insert into a values (2); 
insert into a values (3); 

questa query restituisce 12 righe (SQL Fiddle).

select id, level as lvl 
    from a 
connect by level <= 2 
    order by id, level 

Una riga per ogni nella tabella A con il valore della colonna LVL essere 1 e tre per ciascuna nella Tabella A dove il LVL colonna è 2, cioè:

 
ID | LVL 
---+----- 
1 | 1 
1 | 2 
1 | 2 
1 | 2 
2 | 1 
2 | 2 
2 | 2 
2 | 2 
3 | 1 
3 | 2 
3 | 2 
3 | 2 

È equivalente a questa query, che restituisce gli stessi risultati.

select id, level as lvl 
    from dual 
    cross join a 
connect by level <= 2 
    order by id, level 

Non capisco perché queste query restituiscono 12 righe o perché ci sono tre righe in cui LVL è 2 e unico dove LVL è di 1 per ogni valore della colonna ID.

Aumentare il numero di livelli "connessi" a 3 returns 13 rows per ciascun valore di ID. 1 dove LVL è 1, 3 dove LVL è 2 e 9 dove LVL è 3. Ciò sembra suggerire che le righe restituite siano il numero di righe nella tabella A alla potenza del valore di LVL meno 1.

I sarebbe hanno però che queste query sarebbe lo stesso come il seguente, che restituisce 6 righe

select id, lvl 
    from (select level as lvl 
      from dual 
     connect by level <= 2 
       ) 
cross join a 
order by id, lvl 

il documentation non è particolarmente chiaro, per me, per spiegare quello che dovrebbe accadere. Cosa sta succedendo con questi poteri e perché le prime due domande non sono le stesse della terza?

+0

Abbiamo qualcosa in MySQL 5, equivalente a questo? – abhijitcaps

risposta

9

Nella prima query, ci si collega solo con il livello. Quindi se il livello < = 1, si ottiene 1 volta ogni record. Se il livello < = 2, si ottiene ogni livello 1 volta (per il livello 1) + N volte (dove N è il numero di record nella tabella).È come se ti unissi alla croce, perché stai solo raccogliendo tutti i record dalla tabella fino al raggiungimento del livello, senza avere altre condizioni per limitare il risultato. Per il livello < = 3, questo viene fatto di nuovo per ciascuno di questi risultati.

Così per 3 record:

  • Lvl 1: 3 di record (tutti con livello 1)
  • Lvl 2: 3 record avendo livello 1 + 3 * 3 record avendo livello 2 = 12
  • Lvl 3: 3 + 3 * 3 + 3 * 3 * 3 = 39 (in effetti, 13 record ciascuno).
  • Lvl 4: inizia a vedere uno schema? :)

Non si tratta di un cross join. Un cross join restituirebbe solo quei record che hanno il livello 2 in questo risultato di query, mentre con questo connect by, ottieni i record con livello 1 e i record con livello 2, risultando in 3 + 3 * 3 invece di solo 3 * 3 record.

1

si confrontano le mele con le arance quando si confronta la query finale con le altre mentre il LIVELLO è isolato in quella alla tabella doppia 1 fila.

Consente di considerare questa query:

select id, level as lvl 
    from a 
connect by level <= 2 
    order by id, level 

quello che sta dicendo è, iniziare con la tavola (SELECT * FROM a). quindi, per ogni riga restituita connetti questa riga alla riga precedente. poiché non hai definito un join nella connessione, questo è in effetti un join cartesiano, quindi quando hai 3 righe di (1,2,3) 1 join a 2, 1-> 3, 2-> 1, 2 -> 3, 3-> 1 e 3-> 2 e si uniscono anche a se stessi 1-> 1,2-> 2 e 3-> 3. questi join sono level = 2. quindi abbiamo 9 join, ecco perché ottieni 12 righe (3 righe originali "livello 1" più il set cartesiano).

in modo che il numero di righe di output = rowcount + (conteggio delle righe^2)

nell'ultima query che si stanno isolando livello per questo

select level as lvl 
      from dual 
     connect by level <= 2 

che ovviamente restituisce 2 file. questo viene quindi cartesianizzato alle 3 righe originali, dando 6 righe come output.

11

Quando connect by viene utilizzato senza la clausola start with e l'operatore , non vi sono restrizioni sull'unione di righe figlio a una riga padre. E ciò che Oracle fa in questa situazione, restituisce tutte le possibili permutazioni della gerarchia collegando una riga a ogni riga di livello superiore.

SQL> select b 
    2  , level as lvl 
    3  , sys_connect_by_path(b, '->') as ph 
    4  from a 
    5 connect by level <= 2 
    6 ; 

     B  LVL PH 
     ---------- ---------- 
     1   1 ->1 
     1   2 ->1->1 
     2   2 ->1->2 
     3   2 ->1->3 
     2   1 ->2 
     1   2 ->2->1 
     2   2 ->2->2 
     3   2 ->2->3 
     3   1 ->3 
     1   2 ->3->1 
     2   2 ->3->2 
     3   2 ->3->3 

12 rows selected 
+2

'sys_connect_by_path()' <- questa parola chiave ha spiegato tutto. Una delle migliori risposte a questa domanda (non solo in questo argomento). – RIKI

0

È possibile utilizzare la tecnica qui sotto per superare questo problema:

select id, level as lvl 
    from a 
     left outer join (select level l from dual connect by level <= 2) lev on 1 = 1 
order by id