Oracle SQL - 标识顺序值范围

时间:2018-01-11 14:59:30

标签: sql oracle

这是我的表:

ID  Name      Department
1   Michael   Marketing
2   Alex      Marketing
3   Tom       Marketing
4   John      Sales
5   Brad      Marketing
6   Leo       Marketing
7   Kevin     Production

我正在尝试查找ID范围Department = 'Marketing'

Range   From   To
Range1  1      3    
Range2  5      6

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:8)

使用名为Tabibitosan的技术很容易做到这一点。

这项技术的作用是将每个组的行的位置与整个行集进行比较,以便计算出同一组中的行是否彼此相邻。

例如,您的示例数据如下所示:

WITH your_table AS (SELECT 1 ID, 'Michael' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 2 ID, 'Alex' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 3 ID, 'Tom' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 4 ID, 'John' NAME, 'Sales' department FROM dual UNION ALL
                    SELECT 5 ID, 'Brad' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 6 ID, 'Leo' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 7 ID, 'Kevin' NAME, 'Production' department FROM dual)
-- end of mimicking your table with data in it. See the SQL below:
SELECT ID,
       NAME,
       department,
       row_number() OVER (ORDER BY ID) overall_rn,
       row_number() OVER (PARTITION BY department ORDER BY ID) department_rn,
       row_number() OVER (ORDER BY ID) - row_number() OVER (PARTITION BY department ORDER BY ID) grp
FROM   your_table;

        ID NAME    DEPARTMENT OVERALL_RN DEPARTMENT_RN        GRP
---------- ------- ---------- ---------- ------------- ----------
         1 Michael Marketing           1             1          0
         2 Alex    Marketing           2             2          0
         3 Tom     Marketing           3             3          0
         4 John    Sales               4             1          3
         5 Brad    Marketing           5             4          1
         6 Leo     Marketing           6             5          1
         7 Kevin   Production          7             1          6

下面,我' VE整组数据的给定的所有行按升序ID顺序的行数(overall_rn列),和I'已经给每个部门一个行行号(department_rn列),再次按递增的id顺序。

既然我已经这样做了,我们可以从另一个中减去一个(grp列)。

请注意grp列中的数字对于彼此相邻的deparment行保持不变,但每次出现间隙时都会更改。

E.g。对于市场营销部门,第1-3行彼此相邻并且grp = 0,但第4行营销实际上位于整个结果集的第5行,因此它现在具有不同的grp编号。由于第5个营销行位于整个集合的第6行,因此它与第4个营销行具有相同的grp编号,因此我们知道它们彼此相邻。

一旦我们获得了grp信息,就可以在部门和新的grp列上进行聚合查询分组,使用min和max查找开始和结束ID:

WITH your_table AS (SELECT 1 ID, 'Michael' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 2 ID, 'Alex' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 3 ID, 'Tom' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 4 ID, 'John' NAME, 'Sales' department FROM dual UNION ALL
                    SELECT 5 ID, 'Brad' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 6 ID, 'Leo' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 7 ID, 'Kevin' NAME, 'Production' department FROM dual)
-- end of mimicking your table with data in it. See the SQL below:
SELECT department,
       MIN(ID) start_id,
       MAX(ID) end_id
FROM   (SELECT ID,
               NAME,
               department,
               row_number() OVER (ORDER BY ID) - row_number() OVER (PARTITION BY department ORDER BY ID) grp
        FROM   your_table)
GROUP BY department, grp;

DEPARTMENT   START_ID     END_ID
---------- ---------- ----------
Marketing           1          3
Marketing           5          6
Sales               4          4
Production          7          7

注意,我已经认为id列中的空白并不重要(即如果id = 6没有行(所以Leo和Kevin的id分别为7和8)然后Leo和Brad仍会出现在同一组中,其开头id = 5且end id = 7.

如果id列中的间隙计为指示新组,那么您可以使用id来标记整个行集(即不需要计算overall_rn;只需使用id列)。

这意味着您的查询将变为:

WITH your_table AS (SELECT 1 ID, 'Michael' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 2 ID, 'Alex' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 3 ID, 'Tom' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 4 ID, 'John' NAME, 'Sales' department FROM dual UNION ALL
                    SELECT 5 ID, 'Brad' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 7 ID, 'Leo' NAME, 'Marketing' department FROM dual UNION ALL
                    SELECT 8 ID, 'Kevin' NAME, 'Production' department FROM dual)
-- end of mimicking your table with data in it. See the SQL below:
SELECT department,
       MIN(ID) start_id,
       MAX(ID) end_id
FROM   (SELECT ID,
               NAME,
               department,
               ID - row_number() OVER (PARTITION BY department ORDER BY ID) grp
        FROM   your_table)
GROUP BY department, grp;

DEPARTMENT   START_ID     END_ID
---------- ---------- ----------
Marketing           1          3
Sales               4          4
Marketing           5          5
Marketing           7          7
Production          8          8

答案 1 :(得分:-2)

我目前没有环境,但你可以尝试这样的事情

select * from tab1 where id in
(select min(id) from tab1 where Department = 'Marketing'
union 
select max(id) from tab1 where Department = 'Marketing')