如何在oracle中计算范围

时间:2010-08-27 12:20:41

标签: sql oracle range

我有一个定义范围的表格,例如:

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。

4 个答案:

答案 0 :(得分: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

答案 1 :(得分: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());

或者从视图中创建并选择它(如果你想隐藏OBJECT实现):

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/

答案 2 :(得分: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

答案 3 :(得分:0)

我可以给你一个肮脏的解决方案。但请不要嘲笑我:(

  1. 准备一个虚拟表,比如表DUMMY,它只包含一个字段(DUMMY_ID),其值为1..n,其中n足以解决您的问题。我们以n = 100为例。
  2. 加入这两个表,您的实际表和DUMMY表。就像这样:

    选择  DUMMY_ID,  MAP 从  DUMMY,  (SELECT STARTENDMAP FROM ACTUAL)AS ACTUAL 哪里   在DUMMY_IDSTART

  3. 之间END {。}}

    请注意,上面给出的查询是MySQL。我没有长时间使用Oracle,但确定你明白了。