2011-03-24 68 views
4

我試圖寫一個查詢,將返回SQL服務器 - 選擇頂層2行

  1. 最近AccountDate爲0的記錄每locationID
  2. 然後每locationID第二最近AccountDate。該記錄可以是1或0
  3. 如果有兩個AccountDates具有相同的日期,然後返回基於DateAccountLoaded

如何過我的解決方案看起來並不很優雅最近AccountDate。有沒有人有更好的方式來實現這一點。

請參考下面我的解決方案

CREATE TABLE [dbo].[TopTwoKeyed](
ID INT IDENTITY(1,1) PRIMARY KEY(ID), 
[LocationID] [int] NULL, 
[AccountDate] [date] NULL, 
[Record] [tinyint] NULL, 
[DateAccountLoaded] [date] NULL 
) 

INSERT INTO [dbo].[TopTwoKeyed] (
     [LocationID], 
     AccountDate, 
     Record, 
     DateAccountLoaded 
     ) 

VALUES(1,'2009-10-31',0,'2011-03-23'), 
(1,'2008-10-31',1,'2011-03-23'), 
(1,'2008-10-31',0,'2010-03-22'), 
(1,'2008-10-31',1,'2009-03-23'), 
(1,'2011-10-31',1,'2010-03-22'), 
(1,'2009-10-31',0,'2010-03-23'), 
(2,'2011-10-31',0,'2010-03-23'), 
(2,'2010-10-31',0,'2010-03-23'), 
(2,'2010-10-31',1,'2010-03-23'), 
(2,'2010-10-31',1,'2009-03-23'), 
(3,'2010-10-31',0,'2010-03-23'), 
(3,'2009-10-31',0,'2010-03-23'), 
(3,'2008-10-31',1,'2010-03-23') 




    -- Get the most recent Account Date per locationID which has a record type of 0 
    SELECT f.LocationID 
      ,f.AccountDate 
      ,f.DateAccountLoaded 
    FROM (
      SELECT ROW_NUMBER() OVER (PARTITION BY LocationID ORDER BY AccountDate DESC,DateAccountLoaded DESC) AS RowNumber 
        ,LocationID AS LocationID 
        ,AccountDate AS AccountDate 
        ,DateAccountLoaded AS DateAccountLoaded 
      FROM [dbo].[TopTwoKeyed] 
      WHERE Record = 0 
      ) f 
    WHERE f.RowNumber = 1 

    UNION ALL 

    SELECT ff.LocationID 
      ,ff.AccountDate 
      ,ff.DateAccountLoaded 
    FROM (
      -- Get the SECOND most recent AccountDate. Can be either Record 0 or 1. 
      SELECT ROW_NUMBER() OVER (PARTITION BY LocationID ORDER BY AccountDate DESC,DateAccountLoaded DESC) AS RowNumber 
        ,LocationID AS LocationID 
        ,AccountDate AS AccountDate 
        ,DateAccountLoaded 'DateAccountLoaded' 
      FROM [dbo].[TopTwoKeyed] tt 
      WHERE EXISTS 
        (
        -- Same query as top of UNION. Get the most recent Account Date per locationID which has a record type of 0 
        SELECT 1 
        FROM (
          SELECT ROW_NUMBER() OVER (PARTITION BY LocationID ORDER BY AccountDate DESC,DateAccountLoaded DESC) AS RowNumber 
            ,LocationID AS LocationID 
            ,AccountDate AS AccountDate 
          FROM [dbo].[TopTwoKeyed] 
          WHERE Record = 0 
          ) f 
        WHERE f.RowNumber = 1 
        AND  tt.LocationID = f.LocationID 
        AND  tt.AccountDate < f.AccountDate 
        ) 
      ) ff 
    WHERE ff.RowNumber = 1 

-- DROP TABLE [dbo].[TopTwoKeyed] 

回答

2

你可以使用子查詢row_number找到最近的結算日。然後你可以outer apply尋找下一個最近的帳戶日期:

select MostRecent.LocationID 
,  MostRecent.AccountDate 
,  SecondRecent.AccountDate 
from (
     select row_number() over (partition by LocationID order by 
        AccountDate desc, DateAccountLoaded desc) as rn 
     ,  * 
     from TopTwoKeyed 
     where Record = 0 
     ) MostRecent 
outer apply 
     (
     select top 1 * 
     from TopTwoKeyed 
     where Record in (0,1) 
       and LocationID = MostRecent.LocationID 
       and AccountDate < MostRecent.AccountDate 
     order by 
       AccountDate desc 
     ,  DateAccountLoaded desc 
     ) SecondRecent 
where MostRecent.rn = 1 

編輯:爲了將低於海誓山盟行,你可能必須使用union。單個row_number無法工作,因爲第二行對Record列有不同的標準。

; with Rec0 as 
     (
     select ROW_NUMBER() over (partition by LocationID 
        order by AccountDate desc, DateAccountLoaded desc) as rn 
     ,  * 
     from TopTwoKeyed 
     where Record = 0 
     ) 
,  Rec01 as 
     (
     select ROW_NUMBER() over (partition by LocationID 
        order by AccountDate desc, DateAccountLoaded desc) as rn 
     ,  * 
     from TopTwoKeyed t1 
     where Record in (0,1) 
       and not exists 
       (
       select * 
       from Rec0 t2 
       where t2.rn = 1 
         and t1.LocationID = t2.LocationID 
         and t2.AccountDate < t1.AccountDate 
       ) 
     ) 
select * 
from Rec0 
where rn = 1 
union all 
select * 
from Rec01 
where rn = 1 
+0

很聰明。我沒有真正考慮過使用APPLY,但它似乎非常適合這項工作。唯一的問題是,我應該說明的是,我真的需要彼此之間的日期而不是除了(比如連接)之外。非常感謝您的幫助,我會將語法添加到我的SQL工具框中。 – Pixelated 2011-03-24 16:47:13

+0

@FairFunk:回答編輯,只有比你原來的東西簡單的是公用表表達式 – Andomar 2011-03-24 17:08:42

+0

Andomars第二個soltuion應該讀取'和t2.AccountDate Pixelated 2013-06-20 08:37:48