Home > Software design >  Two dependent aggregate functions in one SELECT statement, is that possible?
Two dependent aggregate functions in one SELECT statement, is that possible?

Time:04-20


let me show You a simple table at first:

inr party_id ver
00020222 00020107 0001
00006692 00006693 0025
00021768 00006693 0006
00024726 00006693 0001
00024727 00006693 0000
00006691 00006692 0018
00021949 00006692 0000
00024728 00006692 0000
00024928 00006692 0000

Look at the value '00006693'. I have to get max value from ver column: this will be '0025' in this case. However, if all values in the column are the same, then I have to get max value from inr column. this will be '00024727' in this case. The result should eventually look like:

inr party_id ver
00020222 00020107 0001
00006692 00006693 0025
00006691 00006692 0018

My question is, how to get this data by using two max() functions? I am not good at analytical issues.

I will also add an image, where the problem is described (I think) better and please base on it:

enter image description here

CodePudding user response:

I can offer two options. Simple solution - just sort by "ver desc, inr desc" within party_id group:

with test_data as (
  select '00020222' inr,    '00020107' party_id,    '0001' ver union
  select '00006692',    '00006693', '0025' union
  select '00021768',    '00006693', '0006' union
  select '00024726',    '00006693', '0001' union
  select '00024727',    '00006693', '0000' union
  select '00006691',    '00006692', '0018' union
  select '00021949',    '00006692', '0000' union
  select '00024728',    '00006692', '0000' union
  select '00034567',    '00019734', '0022' union
  select '00064657',    '00019734', '0022'
)
select
  r.inr, r.party_id, r.ver
from 
(  
  select 
    t.*, 
    row_number() over(partition by t.party_id order by t.ver desc, t.inr desc) rn
  from
    test_data t
) r
where
  r.rn = 1

Second solution more verbose, but implements your logic directly:

with test_data as (
  select '00020222' inr,    '00020107' party_id,    '0001' ver union
  select '00006692',    '00006693', '0025' union
  select '00021768',    '00006693', '0006' union
  select '00024726',    '00006693', '0001' union
  select '00024727',    '00006693', '0000' union
  select '00006691',    '00006692', '0018' union
  select '00021949',    '00006692', '0000' union
  select '00024728',    '00006692', '0000' union
  select '00034567',    '00019734', '0022' union
  select '00064657',    '00019734', '0022'
)
select 
  r.inr, r.party_id, r.ver
from
(  
  select 
    t.*,
    case when count(distinct t.ver) over(partition by t.party_id) == 1 then 1 else 0 end is_all_ver_same,
    row_number() over(partition by t.party_id order by t.ver desc) max_ver,
    row_number() over(partition by t.party_id order by t.inr desc) max_inr
  from 
    test_data t
) r   
where 
  (r.is_all_ver_same = 1 and r.max_inr = 1) or (r.is_all_ver_same = 0 and r.max_ver = 1)

CodePudding user response:

I think it's not doable in one select statement since window functions has their limitations but what you need can be solved with a subquery with a ROW_NUMBER() function for ordering:

select 
    inr,
    party_id,
    ver
from
    (
        select
            row_number() over (partition by party_id order by ver desc, inr desc) as rn_ver,
            *
        from #Temp
    ) a
where rn_ver = 1
  • Related