如何从组中选择所有行,直到出现值

问题描述:

我试图从同一个Group中提取所有行,直到我打断点值B。下面的示例数据是有序的虚拟表格:如何从组中选择所有行,直到出现值

+----+--------+------------+ 
| ID | Group | Breakpoint | 
+----+--------+------------+ 
| 1 | 1  | A   | 
| 2 | 1  | A   | 
| 3 | 1  | B   | 
| 4 | 1  | A   | 
| 5 | 2  | A   | 
| 6 | 2  | A   | 
| 7 | 2  | A   | 
| 8 | 3  | A   | 
| 9 | 3  | B   | 
+----+--------+------------+ 

这将是我的结果。

+----+--------+------------+ 
| ID | Group | Breakpoint | 
+----+--------+------------+ 
| 1 | 1  | A   | 
| 2 | 1  | A   | 
| 5 | 2  | A   | 
| 6 | 2  | A   | 
| 7 | 2  | A   | 
| 8 | 3  | A   | 
+----+--------+------------+ 

注意,当有一组内两个AB断点值,我想有行,直到顺序第一A值。如果像group 2这样的组中只有A的值,我想拥有组中的所有项目。

+0

你的PRIMARY KEY是什么? – Strawberry

+0

对不起,这是一个虚拟表结果,我在上面的例子中添加了一个唯一的键! – ddinchev

+0

也许如果我们从头开始.... – Strawberry

这是一个简单的解决方案,不使用子查询或GROUP BY逻辑。

SELECT t1.ID, t1.Group, t1.Breakpoint 
FROM MyTable AS t1 
LEFT OUTER JOIN MyTable AS t2 
    ON t1.ID >= t2.ID AND t1.`Group` = t2.`Group` AND t2.Breakpoint = 'B' 
WHERE t2.ID IS NULL 

对于每一行t1,试图找到与“B”的另一行t2,在同一组,与先前的ID。如果没有找到,则OUTER JOIN保证t2.ID为NULL。只有等到理想的断点后,情况才会如此。

SQL表格代表无序集合。因此,在特定的行之前没有“之前”或“之后”。

让我假设你有一些列指定了排序。我会叫它id。然后,你可以做你想做的有:

select t.* 
from t 
where t.id < (select min(t2.id) from t t2 where t2.group = t.group and t2.breakpoint = 'B'); 

要得到所有行的时候,如果没有'B'

select t.* 
from t 
where t.id < (select coalesce(min(t2.id), t.id + 1) from t t2 where t2.group = t.group and t2.breakpoint = 'B'); 
+0

当不存在具有'breakpoint ='B''的行时,看起来像OP想要返回所有行。我认为这个查询排除了这些行。 (请参阅OP示例数据中的group = 2行,以及期望的输出。) – spencer7593

从你上面的例子,你是不是真的分组结果。你只需要显示的记录,其中断点答:

Select * From Table 
Where Breakpint ='A' 
+1

请注意,此查询将返回从OP示例输出中排除的行id = 4。 – spencer7593

您可以使用NOT EXISTS

select * 
from your_table t1 
where not exists (
    select 1 
    from your_table t2 
    where t1.group = t2.group and t2.id <= t1.id and t2.breakpoint = 'B' 
) 

ALL可以工作,以及如果你从来没有NULLid

select * 
from your_table t1 
where t1.id < ALL(
    select t2.id 
    from your_table t2 
    where t1.group = t2.group and t2.breakpoint = 'B' 
) 

假设我们按ID列排序,我们可以这样做:

SELECT d.* 
    FROM mytable d 
    LEFT 
    JOIN (SELECT bp.group 
       , MIN(bp.id) AS bp_id 
      FROM mytable bp 
      WHERE bp.breakpoint = 'B' 
      GROUP BY bp.group 
     ) b 
    ON b.group = d.group 
    WHERE b.bp_id > d.id OR b.bp_id IS NULL 
    ORDER BY d.group, d.id 

这是考虑到情况下,有没有breakpoint='B'行对于给定的group,并返回所有的行为group

请注意,内联视图bbreakpoint='B'行获得的最低id值为每个group。我们可以将外部联接添加到原始表(匹配group),然后在WHERE子句中进行条件测试,以排除每个组的第一个breakpoint='B'后面的行。