T-SQL Multiple grouping

后端 未结 5 855
野性不改
野性不改 2021-01-13 13:46

I have follwing data :

Product Price   StartDate                   EndDate
Apples  4.9     2010-03-01 00:00:00.000     2010-03-01 00:00:00.000
Apples  4.9           


        
相关标签:
5条回答
  • 2021-01-13 14:25

    My approach.

    Data:

    create table t ( producte varchar(50), 
                     price money, 
                     start_date date,
                     end_date date);
    
    insert into t values
    ( 'apple', 4.9, '2012-01-01', '2012-01-01' ),
    ( 'apple', 4.9, '2012-01-02', '2012-01-02' ),
    ( 'apple', 8, '2012-01-04', '2012-01-04' ),
    ( 'cat', 5, '2012-01-01', '2012-01-01' ),
    ( 'cat', 6, '2012-01-02', '2012-01-02' ),
    ( 'cat', 6, '2012-01-03', '2012-01-03' );
    

    Query:

    with start_dates as (
      select 
        t.producte, t.price, t.start_date, t.end_date, t.start_date as gr_date    
      from 
        t left outer join 
        t t1 on 
            t.price = t1.price and                         --new
            t.producte = t1.producte and
            t.start_date = dateadd(day,1, t1.end_date )
      where t1.producte is null
      union all
      select 
          t.producte, t.price, t.start_date,t. end_date, gr_date
      from
          t inner join 
          start_dates t1 on  
            t.price = t1.price and                         --new
            t.producte = t1.producte and
            t.start_date = dateadd(day,1, t1.end_date )
    )
    select t.producte, t.price , min( t.start_date ), max( t.end_date )
    from start_dates t
    group by  t.producte, gr_date  ,t.price
    

    Results:

    | PRODUCTE | PRICE |   COLUMN_2 |   COLUMN_3 |
    ----------------------------------------------
    |    apple |   4.9 | 2012-01-01 | 2012-01-02 |
    |    apple |     8 | 2012-01-04 | 2012-01-04 |
    |      cat |     5 | 2012-01-01 | 2012-01-01 |
    |      cat |     6 | 2012-01-02 | 2012-01-03 |
    

    Explanation

    This is a recursive CTE expression. Base query take inital dates for each group of prices. Recursive query looks for last data with this price.

    0 讨论(0)
  • Here is a SQLFiddle demo

    with t2 as 
    (
    select t1.*,
    (select count(Price) 
      from t 
      where startdate<t1.startdate 
            and Price<>t1.price
            and Product=t1.Product
    )
    rng  
    from t as t1
    )
    select Product,Price,min(startDate),max(EndDate)  
    from t2 group by Product,Price,RNG
    order by 3
    
    0 讨论(0)
  • 2021-01-13 14:40
    SELECT  product, price, MIN(start_date), MAX(end_date)
    FROM    (
            SELECT  product, price, start_date, end_date,
                    ROW_NUMBER() OVER (PARTITION BY product ORDER BY startDate) rn1,
                    ROW_NUMBER() OVER (PARTITION BY product, price ORDER BY startDate) rn2
            FROM    mytable
            ) q
    GROUP BY
            product, price, rn2 - rn1
    ORDER BY
            product, MIN(start_date), price
    
    0 讨论(0)
  • 2021-01-13 14:45

    I believe this is the best-performing solution so far:

    WITH Calc AS (
       SELECT *,
          Grp = DateAdd(day, -Row_Number()
             OVER (PARTITION BY Product, Price ORDER BY StartDate), StartDate
          )
       FROM dbo.PriceHistory
    )
    SELECT Product, Price, FromDate = Min(StartDate), ToDate = Max(StartDate)
    FROM Calc
    GROUP BY Product, Price, Grp
    ORDER BY FromDate;
    

    Try this out yourself

    0 讨论(0)
  • 2021-01-13 14:49

    Here's a suggestion: for each row, you must find the maximum previous date for which the price is different and you Group on that. For example, for any line between 2010-03-11 and 2010-03-16, you must retrieve the date 2010-03-10 because this is the maximum previous date for which the price is different (2.5 versus 4.9). The first row(s) will return a null date but that shouldn't be a problem.

    However, for a very long table, this kind of query could become very slow. Therefore, if you have some speed problem, you should look into the possibility of adding a column and use a cursor to fill it incrementally: you loop through it by date and each time you see a new price, you change its value. The final Grouping is then trivial.

    Here's something:

    Select Product, Price, Min(StartDate) as StartDate, PreviousDate from (
        Select product, price, StartDate, (Select max (StartDate) from table_2 t3 where t3.price <> t2.price and t3.StartDate < t2.StartDate and t3.Product = t2.Product) as previousDate
        from table_2 t2) SQ
    
    Group by Product, Price, PreviousDate
    Order by PreviousDate
    
    0 讨论(0)
提交回复
热议问题