SQL Server - 选择前2行

时间:2021-03-03 09:29:54

I'm attempting to write a query that will return

我正在尝试编写一个将返回的查询

  1. The most recent AccountDate with a record of 0 per locationID
  2. 最新的AccountDate,每个locationID的记录为0
  3. Then the second most recent AccountDate per locationID. The record can be either 1 or 0.
  4. 然后是每个locationID的第二个最近的AccountDate。记录可以是1或0。
  5. If there are two AccountDates with the same date then return the most recent AccountDate based on DateAccountLoaded
  6. 如果有两个具有相同日期的AccountDates,则返回基于DateAccountLoaded的最新AccountDate

How ever my solution doesn't look very elegant. Has anyone got a better way of achieving this.

我的解决方案怎么看起来不太优雅。有没有人有更好的方法来实现这一目标。

Please see below my solution

请参阅下面我的解决方案

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]

1 个解决方案

#1


2  

You could use a row_number subquery to find the most recent account date. Then you can outer apply to search for the next most recent account date:

您可以使用row_number子查询来查找最近的帐户日期。然后,您可以外部申请搜索下一个最近的帐户日期:

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

EDIT: To place the rows below eachother, you probably have to use a union. A single row_number can't work because the second row has different criterium for the Record column.

编辑:要将行放在彼此之下,您可能必须使用联合。单个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

#1


2  

You could use a row_number subquery to find the most recent account date. Then you can outer apply to search for the next most recent account date:

您可以使用row_number子查询来查找最近的帐户日期。然后,您可以外部申请搜索下一个最近的帐户日期:

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

EDIT: To place the rows below eachother, you probably have to use a union. A single row_number can't work because the second row has different criterium for the Record column.

编辑:要将行放在彼此之下,您可能必须使用联合。单个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