Lag() with condition in sql server

后端 未结 3 1886
南旧
南旧 2020-12-15 08:24

i have a table like this:

Number   Price    Type       Date         Time
------   -----    ----    ----------    ---------
23456    0,665     SV     2014/02/         


        
3条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-15 09:03

    Your question (and Anon's excellent answer) is part of the SQL of islands and gaps. In this answer, I will try to examine the "row_number() magic" in detail.

    I've made a simple example based on events in a ballgame. For each event, we'd like to print the previous and next quarter related message:

    create table TestTable (id int identity, event varchar(64));
    insert TestTable values
        ('Start of Q1'),
        ('Free kick'),
        ('Goal'),
        ('End of Q1'),
        ('Start of Q2'),
        ('Penalty'),
        ('Miss'),
        ('Yellow card'),
        ('End of Q2');
    

    Here's a query showing off the "row_number() magic" approach:

    ; with  grouped as
            (
            select  *
            ,       row_number() over (order by id) as rn1
            ,       row_number() over (
                        partition by case when event like '%of Q[1-4]' then 1 end 
                        order by id) as rn2
            from    TestTable
            )
    ,       order_in_group as
            (
            select  *
            ,       rn1-rn2 as group_nr
            ,       row_number() over (partition by rn1-rn2 order by id) as rank_asc
            ,       row_number() over (partition by rn1-rn2 order by id desc)
                        as rank_desc
            from    grouped
            )
    select  *
    ,       lag(event, rank_asc) over (order by id) as last_event_of_prev_group
    ,       lead(event, rank_desc) over (order by id) as first_event_of_next_group
    from    order_in_group
    order by
            id
    
    • The first CTE called "grouped" calculates two row_number()s. The first is 1 2 3 for each row in the table. The second row_number() places pause announcements in one list, and other events in a second list. The difference between the two, rn1 - rn2, is unique for each section of the game. It's helpful to check difference in the example output: it's in the group_nr column. You'll see that each value corresponds to one section of the game.
    • The second CTE called "order_in_group" determines the position of the current row within its island or gap. For an island with 3 rows, the positions are 1 2 3 for the ascending order, and 3 2 1 for the descending order.
    • Finally, we know enough to tell lag() and lead() how far to jump. We have to lag rank_asc rows to find the final row of the previous section. To find the first row of the next section, we have to lead rank_desc rows.

    Hope this helps clarifying the "magic" of Gaps and Islands. Here is a working example at SQL Fiddle.

提交回复
热议问题