简体   繁体   中英

T-SQL grouping data with condition

I have some data:

period | id_account | float_value
24217 | 303003 | 0
24218 | 303003 | 0
24219 | 303003 | 1
24220 | 303003 | 1
24221 | 303003 | 0
24222 | 303003 | 0

I need to group this data like that:

begin_period | end_period| id_account | float_value     
24217       | 24218     | 303003    |   0   
24219       | 24220     | 303003    |   1   
24221       | 24222     | 303003    |   0   

I tried row_number by partition and while loop but it didn't work.

I understand this as a gaps-and-isald problem, where you want to group together "adjacent" rows, ie rows having the same float_value , across records having the same id_account and parameter .

Here, I think the simplest approch is to use the difference between row numbers to compute which group each record belongs to:

select
    min(period) begin_period,
    max(period) end_period,
    id_account,
    parameter,
    float_value
from (
    select 
        t.*,
        row_number() over(partition by id_account, parameter order by period) rn1,
        row_number() over(partition by id_account, parameter, float_value order by period) rn2
    from mytable t
) t
group by id_account, parameter, float_value, rn1 -rn2
order by id_account, parameter, begin_period

Demo on DB Fiddle :

begin_period | end_period | id_account | parameter      | float_value
-----------: | ---------: | ---------: | :------------- | ----------:
       24217 |      24218 |     303003 | ACCOUNT_STATUS |           0
       24219 |      24220 |     303003 | ACCOUNT_STATUS |           1
       24221 |      24222 |     303003 | ACCOUNT_STATUS |           0

This is a gaps and islands problem, and one approach is to use the difference in row numbers method:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY ID_Account ORDER BY Period) rn1,
        ROW_NUMBER() OVER (PARTITION BY ID_Account, Float_Value ORDER BY Period) rn2
    FROM yourTable
)

SELECT
    MIN(Period) AS Begin_Period,
    MAX(Period) AS End_Period,
    ID_Account,
    MAX(Parameter) AS Parameter,   -- assuming Parameter just always has the same value
    Float_Value
FROM cte
GROUP BY
    ID_Account,
    Float_Value,
    rn1 - rn2
ORDER BY
    MIN(Period);

下面演示链接的屏幕截图

Demo

You can use row_number as following. Here is the demo .

with cte as
(
  select
     *,
     rn - row_number() over(order by Float_Value, rn) as nrnk
  from
  (
    select
      *,
      row_number() over (order by Period) as rn
    from Table1
  ) subq
)

select
  min(Period) as Begin_Period,
  max(Period) as End_Period,
  ID_Account,
  Parameter,
  Float_Value
from cte
group by
  ID_Account,
  Parameter,
  Float_Value,
  nrnk

output:

 Begin_Period   End_Period     ID_Account     Parameter   Float_Value
---------------------------------------------------------------------
 24217            24218          303003    ACCOUNT_STATUS   0
 24221            24222          303003    ACCOUNT_STATUS   0
 24219            24220          303003    ACCOUNT_STATUS   1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM