SQL 服务器 : how to find the record where a field is X for the first time and there are no later records where it isn't

标签 sql sql-server common-table-expression

我现在已经尝试了很长一段时间,但无法弄清楚如何在不使用游标的情况下最好地做到这一点。我想要做的(在 SQL Server 中)是:

  • 找到最早的(按日期)Criterion=1 并且后面没有Criterion=0 的每个Name类别

或者换一种说法:

  • 找到 Criterion 变为 1 且此后不再变为 0 的Date(对于每个NameCategory ).

我猜某种 CTE 似乎是有道理的,但不幸的是,这不是我的强项。因此,我尝试嵌套查询以查找 Criterion=0 的最新记录,然后选择下一条记录(如果有的话),但我得到的结果不正确。另一个挑战是返回一条记录,其中只有 Criterion=1 的 NameCategory 记录。

这是示例数据:

Name    Category    Criterion     Date
------------------------------------------------    
Bob     Cat1        1             22.11.16 08:54   X 
Bob     Cat2        0             21.02.16 02:29    
Bob     Cat3        1             22.11.16 08:55    
Bob     Cat3        0             22.11.16 08:56    
Bob     Cat4        0             21.06.12 02:30    
Bob     Cat4        0             18.11.16 08:18    
Bob     Cat4        1             18.11.16 08:19    
Bob     Cat4        0             22.11.16 08:20    
Bob     Cat4        1             22.11.16 08:50   X    
Bob     Cat4        1             22.11.16 08:51    
Hannah  Cat1        1             22.11.16 08:54   X    
Hannah  Cat2        0             21.02.16 02:29    
Hannah  Cat3        1             22.11.16 08:55
Hannah  Cat3        0             22.11.16 08:56

行后带有 X 的行是我要检索的行。

最终可能并没有那么复杂......

最佳答案

如果您只需要名称、类别和日期:

select name, category, min(date)
from t
where criterion = 1 and
      not exists (select 1
                  from t t2
                  where t2.name = t.name and t2.category = t.category and
                        t2.criterion = 0 and t2.date >= t.date
                 )
group by name, category;

有更奇特的方法来获取这些信息,但这是一种相对简单的方法。

实际上,更奇特的方法并不是特别复杂:

select t.*
from (select t.*,
             min(case when date > maxdate_0 or maxdate_0 is NULL then date end) over (partition by name, category) as mindate_1
      from (select t.*,
                   max(case when criterion = 0 then date end) over (partition by name, category) as maxdate_0
            from t
           ) t
      where criterion = 1
     ) t
where mindate_1 = date;

编辑:

SQL Fiddle 这些天似乎不起作用。以下对我有用(使用 Postgres):

with t(name, category, criterion, date) as (
    values ('Bob', 'Cat1', 1, '2016-11-16 08:54'),
           ('Bob', 'Cat2', 0, '2016-02-21 02:29'), 
           ('Bob', 'Cat3', 1, '2016-11-16 08:55'), 
           ('Bob', 'Cat3', 0, '2016-11-16 08:56'), 
           ('Bob', 'Cat4', 0, '2012-06-21 02:30'), 
           ('Bob', 'Cat4', 0, '2016-11-18 08:18'), 
           ('Bob', 'Cat4', 1, '2016-11-18 08:19'),
           ('Bob', 'Cat4', 0, '2016-11-22 08:20'),    
           ('Bob', 'Cat4', 1, '2016-11-22 08:50'),  
           ('Bob', 'Cat4', 1, '2016-11-22 08:51'), 
           ('Hannah', 'Cat1', 1, '2016-11-22 08:54'),    
           ('Hannah', 'Cat2', 0, '2016-02-21 02:29'),   
           ('Hannah', 'Cat3', 1, '2016-11-22 08:55'),
           ('Hannah', 'Cat3', 0, '2016-11-22 08:56')
          )
select t.*
from (select t.*,
             min(case when date > maxdate_0 or maxdate_0 is NULL then date end) over (partition by name, category) as mindate_1
      from (select t.*,
                   max(case when criterion = 0 then date end) over (partition by name, category) as maxdate_0
            from t
           ) t
      where criterion = 1
     ) t
where mindate_1 = date;

关于SQL 服务器 : how to find the record where a field is X for the first time and there are no later records where it isn't,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40729050/

相关文章:

mysql - 分组依据但选择确切记录(如果存在)

SQL Server 四舍五入问题到小数点后两位

sql-server - 如何在运行时在 DatabaseGeneeratedOption.Identity、Compulated 和 None 之间切换,而不必生成空的 DbMigrations

sql - 从 CTE 更新表中的记录

SQL Server 选择多个值,如果没有找到值,则返回 null

sql - 选择每组的最大值

c# - 在 asp.net 中传递双引号

sql - 如何避免此子查询并创建索引 View ?

sql - 具有递归 CTE : sorting/ordering children by popularity while retaining tree structure (parents always above children) 的 Postgres

postgresql - DISTINCT 超过巨大的 unnest