2010-08-27 10 views
6

Ho una tabella che definisce gli intervalli, ad esempio:come CALC gamme in Oracle

START | END | MAP 
1  | 10 | A 
11 | 15 | B 
... 

come faccio query in quel tavolo in modo che il risultato sarà

ID | MAP 
1 | A 
2 | A 
3 | A 
4 | A 
5 | A 
6 | A 
7 | A 
8 | A 
9 | A 
10 | A 
11 | B 
12 | B 
13 | B 
14 | B 
15 | B 
... 

Scommetto suo un facile uno ... Grazie per l'aiuto

f.

+0

I dati (nella tabella degli intervalli) possono essere visualizzati in questo modo? (Voglio dire, quando C si estende a un altro intervallo.) START | FINE | MAP 1 | 10 | A 11 | 15 | B 5 | 14 | C –

risposta

7
select * from Table, (Select Level as Id from dual connect by Level <= (Select Max(End)  from Table)) t 
Where t.Id between rr.Start and rr.End 
Order by Map, Start, Id 
+0

Ho molte buone risposte qui, specialmente quel ragazzo con il grande articolo. Ma questo è semplice, ordinato e fatto! Grazie amico! f. – filippo

0
WITH r AS 
     (
     SELECT MAX(end - start) + 1 AS mr 
     FROM  ranges 
     ), 
     series AS 
     (
     SELECT level - 1 AS l 
     FROM  dual 
     CONNECT BY 
       level <= 
       (
       SELECT mr 
       FROM r 
       ) 
     ) 
SELECT start + l, map 
FROM ranges 
JOIN series 
ON  l <= end - start 

In PostgreSQL, si può solo fare:

SELECT map, generate_series(start, end) 
FROM ranges 

Aggiornamento:

Testato sul tuo dati di esempio:

WITH ranges AS 
     (
     SELECT 1 AS f_start, 10 AS f_end, 'A' AS map 
     FROM dual 
     UNION ALL 
     SELECT 11 AS f_start, 15 AS f_end, 'B' AS map 
     FROM dual 
     ), 
     r AS 
     (
     SELECT MAX(f_end - f_start) + 1 AS mr 
     FROM  ranges 
     ), 
     series AS 
     (
     SELECT level - 1 AS l 
     FROM  dual 
     CONNECT BY 
       level <= 
       (
       SELECT mr 
       FROM r 
       ) 
     ) 
SELECT f_start + l, map 
FROM ranges 
JOIN series 
ON  l <= f_end - f_start 
ORDER BY 
     2, 1 
+0

generate_series() è così bello;) –

+0

questo non funziona davvero .. restituito solo un paio di righe ... – filippo

+0

@flpgdt: vedere l'aggiornamento del post, funziona con i dati che hai fornito. – Quassnoi

0

Posso darti una soluzione sporca. Ma per favore non ridere di me :(

  1. preparare una tabella fittizia, dicono tavolo FINTA che contiene un solo campo (DUMMY_ID), che i suoi valori sono 1..n dove n è abbastanza grande per il vostro problema. Diamo prendere n = 100 per esempio
  2. unire queste due tabelle, la vostra tabella effettiva e la tabella DUMMY Proprio come questo:..

    SELEZIONA DUMMY_ID, MAP dA DUMMY, (SELECT START, END, MAP DA ACTUAL) AS ACTUAL DOVE DUMMY_ID TRA START E END

nota che, dato query di cui sopra è MySQL. Non ho usato Oracle per molto tempo ma sono sicuro che hai capito il punto.

2

Questa soluzione a prima vista sembra complicata, ma in genere risolve qualsiasi intervallo. Risolvi il problema con VALUE che potrebbero interferire con qualsiasi altro intervallo.

In primo luogo creare tabella di esempio e inserire i dati:

create table test_table (col_START NUMBER, col_END NUMBER, col_MAP CHAR(1)); 
insert into test_table(col_START, col_END, col_MAP) values(1,10,'A'); 
insert into test_table(col_START, col_END, col_MAP) values(11,15,'B'); 
insert into test_table(col_START, col_END, col_MAP) values(5,12,'C'); 

Ora i dati appaiono così:

START | END | MAP 
1  | 10 | A 
11 | 15 | B 
5  | 12 | C 

Ora creare tipo di oggetto:

CREATE TYPE SampleType AS OBJECT 
(
    id number, 
    map_string varchar2(2000) 
) 
/

CREATE TYPE SampleTypeSet AS TABLE OF SampleType 
/

e anche creare FUNZIONE pipeline:

CREATE OR REPLACE FUNCTION GET_DATA RETURN SampleTypeSet 
PIPELINED 
IS 
    l_one_row SampleType := SampleType(NULL, NULL); 

BEGIN 

    FOR cur_data IN (select col_START, col_END, col_MAP from test_table) LOOP 
     FOR i IN cur_data.col_START..cur_data.col_END LOOP 
      l_one_row.id := i; 
      l_one_row.map_string := cur_data.col_MAP; 
      PIPE ROW(l_one_row); 
     END LOOP; 
    END LOOP; 

    RETURN; 
END GET_DATA; 
/

Infine è possibile utilizzare query semplice:

SELECT * FROM TABLE(GET_DATA()); 

O creare e selezionarlo dalla vista (se si desidera implementazione OGGETTO nascondere):

CREATE VIEW VIEW_ALL_DATA AS SELECT * FROM TABLE(GET_DATA()); 
SELECT * FROM VIEW_ALL_DATA; 

Sulla base di questo mio articolo:

http://martin-mares.cz/2010/08/oracle-db-pipelined-function/