2010-08-27 41 views
6

我定義範圍內的表,比如:如何calc下範圍在Oracle

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

我怎麼查詢到該表,所以其結果將是

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

我敢打賭,它是一個簡單的一...感謝您的幫助

f。

+0

數據(在範圍表中)看起來像這樣嗎? (我的意思是,當C延伸到另一個範圍時。) START | END |地圖 1 | 10 | A 11 | 15 | B 5 | 14 | C – 2010-08-27 13:15:10

回答

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

我在這裏有很多很好的答案,特別是那個有大文章的人。但是這個很簡單,排序並且做到了! 謝謝隊友! f。 – filippo 2010-08-27 14:18:58

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 

PostgreSQL,你可以只是做:

SELECT map, generate_series(start, end) 
FROM ranges 

更新:

測試你的樣本數據:

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()很酷;) – 2010-08-27 12:45:31

+0

這沒有真正的工作..它只返回我的幾行或... – filippo 2010-08-27 12:53:16

+0

@ flpgdt:看到後更新,它適用於您提供的數據。 – Quassnoi 2010-08-27 12:59:25

0

我可以給你一個骯髒的解決方案。但是,請不要嘲笑我:(

  1. 準備一個虛表,說哪隻包含一個字段(DUMMY_ID),它的值是1..1其中n是足夠大,你的問題表假人。我們取n = 100例如
  2. 連接這兩個表,您的實際表和虛表就像這樣:。

    選擇 DUMMY_IDMAP FROM DUMMY, (SELECT STARTENDMAP FROM ACTUAL)AS ACTUAL WHERE,鑑於上面的查詢 DUMMY_ID之間STARTEND

注意是MySQL的。我很長一段時間沒有使用Oracle,但肯定你明白了。

2

這個解決方案乍一看看起來很複雜,但通常可以解決任何範圍。解決可能會受到其他範圍干擾的VALUE問題。

首先創建示例表並插入數據:

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

現在的數據是這樣的:

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

現在創建對象類型:

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

CREATE TYPE SampleTypeSet AS TABLE OF SampleType 
/

而且也創造了管道函數:

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; 
/

最後,你可以使用簡單的查詢:

SELECT * FROM TABLE(GET_DATA()); 

或創建並從視圖中選擇它(如果你想隱藏對象實現):

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

基於此我的文章:

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