SQL 查询:每次特定参数获取特定值时,如何select 所有后续行

SQL query: How to select all following rows every time specific parameter acquires specific value

在我的数据库中,我有一个包含 3 列的 table:日期时间、参数、值。我的目标是获取数据的一个子集。我想获取参数 = 'B' 和值 > 5 之后的所有行(将此行包含在结果集中)。省略参数 = 'B' 和值 <=5 之后的所有行(将此行包含在结果集中)。

source table and expected result

换句话说,我想在参数为 B 的行中使用 VALUE 作为标志(伪代码):


    include_flag = 0
    result_set = empty table
    
    for row in rows:
        if parameter = B and value > 5:
            result_set.append(row)
            include_flag = 1
        elif parameter = B and value <= 5:
            result_set.append(row)
            include_flag = 0
        elif parameter <> B:
            if include_flag = 1:
                result_set.append(row)
            elif include_flag = 0:
                skip(row)

来源table:

date_time parameter value
1.9.2021 12:34:00 A 0.50
2.9.2021 14:01:00 B 7.40
2.9.2021 21:52:00 C 85.40
3.9.2021 3:15:00 B 3.80
4.9.2021 1:42:00 C 67.30
5.9.2021 12:34:00 A 0.3
6.9.2021 12:34:00 C 76.50
6.9.2021 17:22:00 A 0.40
6.9.2021 19:37:00 B 8.10
7.9.2021 12:34:00 C 91.70
7.9.2021 22:12:00 C 87.60
8.9.2021 7:17:00 A 0.60
9.9.2021 5:34:00 B 5.80
9.9.2021 12:34:00 B 4.90
10.9.2021 19:56:00 A 0.60

想要的结果集:

date_time parameter value
2.9.2021 14:01:00 B 7.40
2.9.2021 21:52:00 C 85.40
3.9.2021 3:15:00 B 3.80
6.9.2021 19:37:00 B 8.10
7.9.2021 12:34:00 C 91.70
7.9.2021 22:12:00 C 87.60
8.9.2021 7:17:00 A 0.60
9.9.2021 5:34:00 B 5.80
9.9.2021 12:34:00 B 4.90

此外,我对导致替代结果集的解决方案感兴趣,该结果集的行数与源 table 相同,但仅包含主要结果集中包含的那些值。 (因此(参数 = 'B' 和值 <=5)之后的行也包括在内,只是忽略了值)

备选结果集:

date_time parameter value
1.9.2021 12:34:00 A NaN
2.9.2021 14:01:00 B 7.40
2.9.2021 21:52:00 C 85.40
3.9.2021 3:15:00 B 3.80
4.9.2021 1:42:00 C NaN
5.9.2021 12:34:00 A NaN
6.9.2021 12:34:00 C NaN
6.9.2021 17:22:00 A NaN
6.9.2021 19:37:00 B 8.10
7.9.2021 12:34:00 C 91.70
7.9.2021 22:12:00 C 87.60
8.9.2021 7:17:00 A 0.60
9.9.2021 5:34:00 B 5.80
9.9.2021 12:34:00 B 4.90
10.9.2021 19:56:00 A NaN

如有任何帮助,我们将不胜感激。

编辑:

查询:

SELECT t.parameter, t.date_time, t.value, B_over_limit = CASE 
   WHEN t.parameter = 'B' AND t.value > 5.0 THEN 1 
   WHEN t.parameter = 'B' AND t.value <= 5.0 THEN 0 
   ELSE null END
FROM table t ORDER BY t.date_time

带来:

date_time parameter value B_over_limit
1.9.2021 12:34:00 A 0.50 null
2.9.2021 14:01:00 B 7.40 1
2.9.2021 21:52:00 C 85.40 null
3.9.2021 3:15:00 B 3.80 0
4.9.2021 1:42:00 C 67.30 null
5.9.2021 12:34:00 A 0.3 null
6.9.2021 12:34:00 C 76.50 null
6.9.2021 17:22:00 A 0.40 null
6.9.2021 19:37:00 B 8.10 1
7.9.2021 12:34:00 C 91.70 null
7.9.2021 22:12:00 C 87.60 null
8.9.2021 7:17:00 A 0.60 null
9.9.2021 5:34:00 B 5.80 1
9.9.2021 12:34:00 B 4.90 0
10.9.2021 19:56:00 A 0.60 null
SELECT s.parameter, s.date_time, s.values, 
LAST_VALUE(s.B_over_limit) OVER(...) FROM subquery s ORDER BY date_time

result of subquery and desired intermediate result

您需要有一个唯一的列 (id) 并使用“OUTER APPLY”以获得预期的结果。

由于您的示例数据没有唯一列,我创建了一个临时的 table 来创建唯一 ID 列并存储示例数据。

  1. 示例输入:

  1. 使用标识列和输入数据中的所有列创建临时 table。
  2. insert Input data into temp table order by date_time 维护数据顺序。

温度 table:

  1. 从此临时 table 编写查询以生成 B_over_limit 列并将其插入另一个临时 table 以供进一步使用。

  1. 现在用outer apply写一个查询,当NULL时获取列的前一个值得到最终结果。

查询:

select * from tb1 --sample source data
order by date_time

--create temp table #t1 (use original table datatypes)
   create table #t1
   (id int identity not null,
    date_time varchar(50), 
    parameter char(1),
    value float
   )

 insert into #t1  insert input into 
 select * from tb1 order by convert(datetime,date_time)

 select * from #t1;

 SELECT id, t.date_time, t.parameter, t.value, 
   B_over_limit = CASE WHEN t.parameter = 'B' AND t.value > 5.0 THEN 1 
                       WHEN t.parameter = 'B' AND t.value <= 5.0 THEN 0 
                       ELSE null 
                   END 
 into #t2
 FROM #t1 t ORDER BY convert(datetime,t.date_time)

 select * from #t2

 select a.date_time, a.parameter, a.value,
     case when id = 1 and a.B_over_limit is NULL then 0 
     else ISNULL(a.B_over_limit, t.B_over_limit) 
     end as B_over_limit
 from #t2 a
 outer apply
   (select top 1 B_over_limit from #t2 b 
       where b.id < a.id and b.date_time is not null 
         and b.parameter is not null and b.value is not null
         and b.B_over_limit is not null
         and a.B_over_limit is null 
       order by id desc ) t