简体   繁体   中英

find the max for each value in SQL

i have tables like this

table 1

|cl.1| 
| -- | 
| a  | 
| b  |
| c  |

table 2

|cl.1|cl.2|para|
|----|---| --- |
| a  | 3 |  t  |
| a  | 3 |  f  |
| b  | 2 |  t  |
| a  | 1 |  b  |
| c  | 4 |  t  |
| b  | 7 |  d  |

i want to get the max value for each element in table1 from table2 and the different parameter so the expecited tabel should be like this

|cl.1|max|para|
|----|---| --- |
| a  | 3 |  t  |
| a  | 3 |  f  |
| c  | 4 |  t  |
| b  | 7 |  d  |

If you are trying to get the max tl.1 and if for the same values it is equal, you could try:

SELECT * 
FROM table2
WHERE cl_2 in  ( SELECT MAX(cl_2) 
                 FROM table2 
                 group by cl_1 
);

Result:

 cl_1 cl_2 para a 3 ta 3 f c 4 tb 7 d

Tested on MySQL : https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=42a6bc20622a210b18101588540995ec

You could use a join, but it makes no difference:

SELECT t1.cl_1,t2.cl_2,t2.para 
FROM table2 t2
INNER JOIN table1 t1 on t2.cl_1=t1.cl_1
WHERE t2.cl_2 in  (SELECT MAX(cl_2) FROM table2 group by cl_1 );

Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=4b2eed9bcee3532cc7c4e7b3862bc3ef

Depends on what features your RDBMS supports.

With Oracle you could do a CROSS APPLY to order table2 by descending cl2 and keep the top values (with ties):

select T1.c1, TM.maximum, TM.para
from Table1 T1
cross apply (
  select *
  from Table2 T2
  where T2.c1 = T1.c1
  order by T2.maximum descending
  fetch first 1 row with ties
) TM

You can do the same in SQL Server with syntax select top 1 with ties instead of fetch first 1 row with ties .

Another option could be to use Analytical Functions to rank the results per col1 and then keep only the first ones.

select T.c1, T.maximum, T.para
from (
  select 
    T1.c1, T2.maximum, T2.para, 
    rank() over (partition by T1.c1 order by T2.maximum desc) r
  from T1
  join T2 on T1.c1 = T2.c2
) T
where T.r = 1

Less stylish and probably(?) less performant would be computing the maximum for each c1 and then doing an equality:

select T1.c1, T2.maximum, T2.para
from T1
join T2 on T1.c1 = T2.c1
where T2.maximum = (select max(maximum) from T2 where c1 = T1.c1)

Use a CTE to get the max values, then select the rows with those values:

with maxes as 
(
    select t1.[cl.1]
        , max(t2.[cl.2]) max_val
    from table1 t1
    inner join table2 t2
        on t1.[cl.1] = t2.[cl.1]
    group by t1.[cl.1]
)
select t1.[cl.1]
    , t2.[cl.2]
    , t2.para
from table1 t1
inner join table2 t2
    on t1.[cl.1] = t2.[cl.1]
where t2.[cl.2] = (select m.max_val from maxes m where m.[cl.1] = t1.[cl.1])

This can also be achieved by joining the CTE:

with maxes as 
(
    select t1.[cl.1]
        , max(t2.[cl.2]) max_val
    from table1 t1
    inner join table2 t2
        on t1.[cl.1] = t2.[cl.1]
    group by t1.[cl.1]
)
select t1.[cl.1]
    , t2.[cl.2]
    , t2.para
from table1 t1
inner join table2 t2
    on t1.[cl.1] = t2.[cl.1]
inner join maxes m
    on t2.[cl.2] = m.max_val

You can try to compute all the maximums:

with Maxes as (
    select cl1,
           max(cl2) as cl2
      from Table2
  group by cl1)

and then join them with the original Table2 , eg

with Maxes as (
    select cl1,
           max(cl2) as cl2
      from Table2
  group by cl1)

select t.*
  from Table2 t inner join
       Maxes m on (t.cl1 = m.cl1 and t.cl2 = m.cl2)

DENSE_RANK can be used to get whole rows that have a maximum of something within a partition.

Because when sorted descending, the top 1 will have rank 1.

select cl_1, cl_2, para
from
(
    select cl_1, cl_2, para
    , dense_rank() over (partition by cl_1 order by cl_2 desc) as rnk
    from table1 t1
    join table2 t2 using (cl_1)
) q
where rnk = 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