【问题标题】:Fetching Specific Group of Rows获取特定的行组
【发布时间】:2018-03-13 23:44:41
【问题描述】:

我有一个包含“名称”、“标志”和其他一些列的表格。我想从表中选择特定的行组。数据已根据另一个时间戳列排序。

 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

【问题讨论】:

  • 没有“第一组”或“最后一组”之类的东西,除非表中有一行指定了顺序。

标签: sql oracle11g


【解决方案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;

【讨论】:

  • 好把戏;虽然如果在最后一个 I 之后有一个 D,或者在第一个 D 之前有一个 I(或任何一端的其他字符),这可能是一个问题......但没有说明这是否可能。
  • 我已经更新了缺失的信息。感谢您指出。但正如约翰所说,开头可能会设置“I”或最后会设置“D”。在这种情况下,这将不起作用。
【解决方案2】:

假设您有某种列来确定结果集的顺序(例如,下面我的查询中的 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 的答案表现更好,但我建议您测试两个答案,看看哪个更适合您的表/索引/数据等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 2017-03-26
    • 2019-10-16
    • 2013-08-29
    • 2017-10-06
    • 2017-02-18
    相关资源
    最近更新 更多