获取特定的行组

时间:2018-03-13 11:29:54

标签: sql oracle11g

我有一个带有'Name','Flag'和其他一些列的表。我想从表中选择特定的行组。数据已根据另一个时间戳列进行排序。

 Name          Flag
------        ------
  A             D
  B             D
  C             D
  D             I
  E             I
  D             D
  E             D
  B             I
  D             I
  F             I

我想获取第一组'D'标志和最后一组'I'标志。是否有可能在SQL(只有选择语句,而不是PL/SQL)?

期望的输出:

 Name          Flag
------        ------
  A             D
  B             D
  C             D
  B             I
  D             I
  F             I

2 个答案:

答案 0 :(得分:1)

SQL表代表无序集。所以,没有"第一"或者"最后",除非你有一个指定排序的列。请注意,这适用于SQL查询和PL / SQL代码。当然,您指定您有两列,因此数据中不存在此类列。

但我要假设你确实有一个。如果是这样,你可以这样做:

select t.*
from t
where (t.flag = 'D' and
       t.orderingcol < (select min(t2.orderingcol) from t t2 where t2.flag <> 'D'
      ) or
      (t.flag = 'I' and
       t.orderingcol > (select max(t2.orderingcol) from t t2 where t2.flag <> 'I'
      )
order by t.orderingcol;

答案 1 :(得分:1)

假设你有一些确定结果集排序的列(例如下面我的查询中的id列),这很容易用Tabibitosan的技术来做:

WITH sample_data AS (SELECT 1 ID, 'A' NAME, 'D' flag FROM dual UNION ALL
                     SELECT 2 ID, 'B' NAME, 'D' flag FROM dual UNION ALL
                     SELECT 3 ID, 'C' NAME, 'D' flag FROM dual UNION ALL
                     SELECT 4 ID, 'D' NAME, 'I' flag FROM dual UNION ALL
                     SELECT 5 ID, 'E' NAME, 'I' flag FROM dual UNION ALL
                     SELECT 6 ID, 'D' NAME, 'D' flag FROM dual UNION ALL
                     SELECT 7 ID, 'E' NAME, 'D' flag FROM dual UNION ALL
                     SELECT 8 ID, 'B' NAME, 'I' flag FROM dual UNION ALL
                     SELECT 9 ID, 'D' NAME, 'I' flag FROM dual UNION ALL
                     SELECT 10 ID, 'F' NAME, 'I' flag FROM dual)
SELECT ID,
       NAME,
       flag
FROM   (SELECT ID,
               NAME,
               flag,
               grp,
               MIN(CASE WHEN flag = 'D' THEN grp END) OVER (PARTITION BY flag) min_d_grp,
               MAX(CASE WHEN flag = 'I' THEN grp END) OVER (PARTITION BY flag) max_i_grp
        FROM   (SELECT ID,
                       NAME,
                       flag,
                       row_number() OVER (ORDER BY ID) - row_number() OVER (PARTITION BY flag ORDER BY ID) grp
                FROM   sample_data
                WHERE  flag IN ('D', 'I')))
WHERE  (flag = 'D' AND grp = min_d_grp)
OR     (flag = 'I' AND grp = max_i_grp)
ORDER BY id;

        ID NAME FLAG
---------- ---- ----
         1 A    D
         3 C    D
         2 B    D
         9 D    I
         8 B    I
        10 F    I

此查询使用tabibitosan方法生成一个额外的“grp”列,然后您可以使用该列查找D标志行的最低编号和I标记行的最高编号。

ETA:这可能会或可能不会比Gordon的回答更好,但我建议您测试两个答案,看看哪个更适合您的表/索引/数据等。