2016-11-21 56 views
2

我已经尝试了相当长一段时间,但无法弄清楚如何在不使用游标的情况下做到最好。我想这样做(在SQL Server)是:SQL Server:如何找到第一次字段为X的记录,并且没有后来的记录不是

  • 找到的最早的(由日期),其中标准 = 1 AND NOT之后标准 = 0每个名称记录类别

或明示的方式不同:

  • 找到日期标准变成1,而不是再次接通之后0(每个名称类别)。

某种形式的CTE似乎是有道理的,但我认为这不是我的强项。所以我尝试嵌套查询找到最新的记录标准 = 0,然后选择下一条记录,如果有一个,但我得到不正确的结果。与此相关的另一个挑战是返回记录,其中只有条件的记录 = 1对于名称类别

这里的样本数据:

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的行是我想要检索的人。

这也许不是所有的中端复杂...

+0

理想的情况下我也想获得名称和类别空记录,如果没有这样的记录(例如鲍勃/ CAT2,鲍勃/的Cat3,汉娜/ CAT2,汉娜/的Cat3,汉娜/ 3,4,5) – Peete

+0

通过“没有遵循“你的意思是否立即跟着?例如1 - > 0还是你也考虑1 - > 1 - > 0作为1,然后是0(最左边的1)? –

+0

是@DuduMarkovitz,最左边的1后面跟着0。尽管如此,间接但随后。 – Peete

回答

4

如果你只是想名称,类别和日期:

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小提琴似乎并不奏效,这些天。以下是为我工作(使用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; 
+0

我试着运行你的第二个查询,它在'mindate_1 = mindate'上抛出一个错误,表示没有声明mindate – DForck42

+0

对于Bob/Cat4,这返回'18.11.16 08:19',但是因为'22.11 .16 08:20',然后再加1,正确的结果应该是'22.11.16 08:50'(倒数第二个记录为Bob/Cat4) – Peete

+0

并且它返回一条记录('22.11.16 08:55' )为Bob/Cat3时,应该没有。 – Peete

1

如何左连接,并过滤NULL?

SELECT yt.Name, yt.Category, yt.Criterion, MIN(yt.Date) AS Date 
FROM YourTable yt 
LEFT JOIN YourTable lj ON lj.Name = yt.Name AND lj.Category = yt.Category AND 
          lj.Criterion != yt.Criterion AND lj.Date > yt.Date 
WHERE yt.Criterion = 1 AND lj.Name IS NULL 
GROUP BY yt.Name, yt.Category, yt.Criterion 
+0

不能得到这个工作 - 为我返回零行...可能是我虽然 – Peete

1

修改答案

select  name,category 
      ,min (date)  as date 

from  (select  name,category,criterion,date 

         ,min (criterion) over 
         (
          partition by name,category 
          order by  date 
          rows   between current row and unbounded following 
         ) as min_following_criterion 

      from  t 
      ) t 

where  criterion  = 1 
     and ( min_following_criterion <> 0 
      or min_following_criterion is null 
      ) 

group by name,category 
+0

谢谢但不是,不仅相邻,但任何以下0 – Peete

+0

@皮特,见修改答案 –

1

也有做特别是窗口功能的途径吨的。该NOT EXISTS,或反注册是更好的方法2,但只是为了好玩这里是与窗口功能做它的发烧友(偷登的用语)的方式之一:

;WITH cte AS (
    SELECT 
     Name 
     ,Category 
     ,CASE WHEN Criterion = 1 THEN Date END as Criterion1Date 
     ,MAX(CASE WHEN Criterion = 0 THEN Date END) OVER (PARTITION BY Name, Category) as MaxDateCriterion0 
    FROM 
     Table 
) 

SELECT 
    Name 
    ,Category 
    ,MIN(Criterion1Date) as Date 
FROM 
    cte 
WHERE 
    ISNULL(MaxDateCriterion0,'1/1/1900') < Criterion1Date 
GROUP BY 
    Name 
    ,Category 

或者作为派生表,如果你不喜欢cte,唯一的区别基本上是将cte嵌套在from子句中。

SELECT 
    Name 
    ,Category 
    ,MIN(Criterion1Date) as Date 
FROM 
    (
     SELECT 
      Name 
      ,Category 
      ,CASE WHEN Criterion = 1 THEN Date END as Criterion1Date 
      ,MAX(CASE WHEN Criterion = 0 THEN Date END) OVER (PARTITION BY Name, Category) as MaxDateCriterion0 
     FROM 
      Table 
    ) t 
WHERE 
    ISNULL(MaxDateCriterion0,'1/1/1900') < Criterion1Date 
GROUP BY 
    Name 
    ,Category 
+0

对于鲍勃/猫4这返回'18.11 .16 08:19',但由于'22.11.16 08:20'为0,接下来是1,所以正确的结果应该是'22.11.16 08:50'(Bob/Cat4倒数第二) 。和戈登的回答一样,也许我的问题并不清楚。 – Peete

+0

同样,当Bob/Cat3应该没有时,它会返回一条记录('22.11.16 08:55')。此外,当Bob/Cat3应该没有时,它会返回一条记录('22.11.16 08:55')。 – Peete

+0

对不起,无视我最后的评论,这工作得很好! – Peete

相关问题