SQL-在满足另一条件的每一行下方选择满足条件的第一行

时间:2020-09-18 20:01:25

标签: sql sql-server

假设我有一个名为Table的表

+----+------+------+
| ID | Col1 | Col2 |
+----+------+------+
|  1 | A    |    0 |
|  2 | B    |    0 |
|  3 | C    |    1 |
|  4 | A    |    1 |
|  5 | D    |    0 |
|  6 | A    |    0 |
|  7 | F    |    1 |
|  8 | H    |    1 |
+----+------+------+

我想要这个结果:

+----+------+------+
| ID | Col1 | Col2 |
+----+------+------+
|  3 | C    |    1 |
|  4 | A    |    1 |
|  7 | F    |    1 |
+----+------+------+

也就是说:

  • 如果Col1 = A且Col2 = 1,则选择相应的行
  • 如果Col1 = A且Col2 = 0,则取其下的第一行,其中Col2 = 1

我尝试过类似的事情

SELECT CASE
       WHEN t.Col2 > 0
         THEN t.Col2
       WHEN t1.Col2 > 0
         THEN t1.Col2
       WHEN t2.Col2 > 0
         THEN t2.Col2
...
FROM Table t
JOIN table t1 ON t.id - 1 = t1.id
JOIN table t2 ON t.id - 2 = t2.id
...
WHERE t.Col2 = 'A'

但这不是我想要的。 我无法提出任何解决方案。我该怎么办?

3 个答案:

答案 0 :(得分:2)

嗯。 。 。我在想lag()

select t.*
from (select t.*,
              lag(col1) over (order by id) as prev_col1,
              lag(col2) over (order by id) as pev_col2
      from t
     ) t
where col1 = 'A' and col2 = 1 or
      (pev_col1 = 'A' and prev_col2 = 0);

答案 1 :(得分:2)

这是一个查询,查找您要求的所有此类行,它们是Col1 = A和Col2 = 1,还是在Col1 = A和Col2 = 0之后的第一个Col2 = 1。

一个简短的解释是查询仅考虑Col2 = 1的行。如果Col1 = A当然需要行。但是如果回头查找Col2 = 1的最接近的前一行以及Col1 = A和Col2 = 0的最接近的前一行,它还会占用该行,并且发现前者比后者更靠后(或者前者没有)不存在。

create table MyTable (
    ID int not null identity(1,1),
    Col1 varchar(100) not null,
    Col2 varchar(100) not null
);

insert MyTable (Col1, Col2) values ('A', '0');
insert MyTable (Col1, Col2) values ('B', '0');
insert MyTable (Col1, Col2) values ('C', '1');
insert MyTable (Col1, Col2) values ('A', '1');
insert MyTable (Col1, Col2) values ('D', '0');
insert MyTable (Col1, Col2) values ('A', '0');
insert MyTable (Col1, Col2) values ('F', '1');
insert MyTable (Col1, Col2) values ('H', '1');

select * from MyTable;

select *
    from MyTable as t
    where t.Col2 = 1
        and (t.Col1 = 'A'
            or isnull((select top (1) t2.ID
                from MyTable as t2
                where t2.ID < t.ID
                    and t2.Col2 = 1
                order by t2.ID desc
                ), 0)
                <
                (select top (1) t2.ID
                from MyTable as t2
                where t2.ID < t.ID
                    and t2.Col1 = 'A'
                    and t2.Col2 = 0
                order by t2.ID desc
                )
            )
    order by t.ID;

答案 2 :(得分:2)

使用窗口函数SUM()和MIN():

with 
  cte1 as (
    select *, sum(case when col1 = 'A' and col2 = 0 then 1 else 0 end) over (order by id) grp
    from tablename
  ),
  cte2 as (
    select *, min(case when col2 = 1 then id end) over (partition by grp order by id) next_id
    from cte1
  )
select id, col1, col2 
from cte2
where (col1 = 'A' and col2 = 1) or (id = next_id)

请参见demo
结果:

> id | col1 | col2
> -: | :--- | ---:
>  3 | C    |    1
>  4 | A    |    1
>  7 | F    |    1