Home > Blockchain >  Aggregate multiple rows to one row, then select which values go to which column SQL
Aggregate multiple rows to one row, then select which values go to which column SQL

Time:08-03

I have a table that looks as follows:

col1 col2 col3 col4 col5 col6 col7
1 ABC ABC1 2904 def
2 ABC ABC2 2400 504 ghi
3 ABC ABC3 504 504 jkl

which needs to be aggregated into one row, looking like this:

col1 col2 col3 col4 col5 col6 col7
1 ABC ABC1 2904 2400 504 def

I understand that it needs to be grouped based on col2. But then what SQL syntax do I need to say that:

  • value of col3 for lowest col1 value stays in col3
  • value of col5 for lowest col1 value goes to col4
  • value of col5 for second col1 value stays in col5
  • value of col5 for highest col1 value goes to col6
  • value of col7 for lowest col1 value stays in col7

CodePudding user response:

Think of this as three different select statements which isolate your min, max and secondary values from Col1. e.g. Select...Where Col1 = 1 (or whatever the min value is), Select...Where Col1 = 2, Select...Where Col1 = max.

Once you have those values broken out you can join all of them together and use the appropriate columns.

I chose to use min, max and row_number in the sub-query because I wasn't sure if your min is always 1 and your secondary value is always 2. If they are, you could write this a bit differently.

select 
    max(Case When a.col1 = mn.MinCol1 Then  a.col1 End) as NewCol1
    ,max(Case When a.col1 = mn.MinCol1 Then  a.col2 End) as NewCol2
    ,max(Case When a.col1 = mn.MinCol1 Then  a.col3 End) as NewCol3
    ,max(Case When a.col1 = mn.MinCol1 Then  a.col5 End) as NewCol4
    ,max(Case When a.col1 = sec.SecondCol1 Then  a.col5 End) as NewCol5
    ,max(Case When a.col1 = mx.MaxCol1 Then  a.col5 End) as NewCol6
    ,max(Case When a.col1 = mn.MinCol1 Then  a.col7 End) as NewCol7
FROM AggTable a
--Get Min Values (Grouped By col2)
LEFT JOIN (Select 
                min(col1) as MinCol1 
                ,col2
          From AggTable
          Group By 
                col2
          ) mn on a.col1 = mn.MinCol1 and a.col2 = mn.col2
--Get Max Values (Grouped By col2)
LEFT JOIN (Select 
                max(col1) as MaxCol1 
                ,col2
            From AggTable
            Group By
                col2
            ) mx on a.col1 = mx.MaxCol1 and a.col2 = mx.col2 
--Get Second Value (Grouped By col2)
LEFT JOIN (select 
            row_number() OVER(Order By col1) as RowNumber
            ,col1  as SecondCol1
            ,col2
          From AggTable
          Group By
                col1
                ,col2
                ) sec on a.col1 = sec.SecondCol1 and a.col2 = sec.col2 and sec.RowNumber = 2

CodePudding user response:

Yet another option is using window functions, given that your DBMS allow them, whereas:

  • FIRST_VALUE is in charge of gathering the first value of "col3" by ordering on "col1"
  • LEAD is in charge of gathering the consecutive values of "col5" by ordering on "col1".

Then you retrieve only the first row with the LIMIT 1 clause.

SELECT col1,
       col2,
       FIRST_VALUE(col3) OVER(ORDER BY col1) AS col3,
       col5                                  AS col4,
       LEAD(col5, 1) OVER(ORDER BY col1)     AS col5,
       LEAD(col5, 2) OVER(ORDER BY col1)     AS col6,
       col7
FROM tab
LIMIT 1
  • Related