oracle中如何计算范围

发布于 2024-09-16 09:31:13 字数 306 浏览 3 评论 0原文

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

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

我打赌它很简单......感谢您的帮助

I have a table defining ranges, e.g.:

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

how do I query into that table so the result will be

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

I bet its a easy one... Thanks for the help

f.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一世旳自豪 2024-09-23 09:31:13
 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
 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
懒猫 2024-09-23 09:31:13

这个解决方案乍一看似乎很复杂,但通常可以解决任何范围。解决可能受到任何其他范围干扰的 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/

This solution at first glance it looks complicated, but generally resolves any range. Solve problem with VALUEs which may be interfered with any other range.

Firstly create sample table and insert data:

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

Now data look like this:

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

Now create object type:

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

CREATE TYPE SampleTypeSet AS TABLE OF SampleType
/

And also create PIPELINED FUNCTION:

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

Finally you can use simple query:

SELECT * FROM TABLE(GET_DATA());

Or create and select it from view (if you want hide OBJECT implementation):

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

Based on this my article:

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

千年*琉璃梦 2024-09-23 09:31:13

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

  1. 准备一个虚拟表,假设表 DUMMY 只包含一个字段(DUMMY_ID),其值为 1..n,其中 n 对于您的问题来说足够大。让我们以 n = 100 为例

  2. 连接这两个表,即您的实际表和虚拟表:

    选择
    DUMMY_ID
    地图

    虚拟
    (从实际中选择开始END地图)AS 实际
    在哪里
    DUMMY_ID BETWEEN START AND END

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

I can give you a dirty solution. But please don't laugh at me :(

  1. Prepare a dummy table, say table DUMMY which contains only one field (DUMMY_ID) which its values are 1..n where n is big enough to your problem. Let's take n = 100 for example.
  2. Join these two tables, your actual table and the DUMMY table. Just like this :

    SELECT
    DUMMY_ID,
    MAP
    FROM
    DUMMY,
    (SELECT START, END, MAP FROM ACTUAL) AS ACTUAL
    WHERE
    DUMMY_ID BETWEEN START AND END

Note that given query above is MySQL. I didn't use Oracle for long time but sure you got the point.

腻橙味 2024-09-23 09:31:13
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
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, you could just do:

SELECT  map, generate_series(start, end)
FROM    ranges

Update:

Tested on your sample data:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文