2016-11-21 45 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

相關問題