简体   繁体   中英

How to find Max value in a column in SQL Server 2012

I want to find the max value in a column

  ID       CName   Tot_Val  PName
  --------------------------------
  1        1       100      P1
  2        1       10       P2
  3        2       50       P2
  4        2       80       P1

Above is my table structure. I just want to find the max total value only from the table. In that four row ID 1 and 2 have same value in CName but total val and PName has different values. What I am expecting is have to find the max value in ID 1 and 2

Expected result:

 ID       CName   Tot_Val   PName
 --------------------------------
  1        1       100      P1
  4        2       80       P1

I need result same as like mention above

 select Max(Tot_Val), CName 
 from table1  
 where PName in ('P1', 'P2')
 group by CName

This is query I have tried but my problem is that I am not able to bring PName in this table. If I add PName in the select list means it will showing the rows doubled eg Result is 100 rows but when I add PName in selected list and group by list it showing 600 rows. That is the problem.

Can someone please help me to resolve this.

One possible option is to use a subquery. Give each row a number within each CName group ordered by Tot_Val . Then select the rows with a row number equal to one.

select x.*
from ( select mt.ID,
              mt.CName,
              mt.Tot_Val,
              mt.PName,
              row_number() over(partition by mt.CName order by mt.Tot_Val desc) as No
       from MyTable mt ) x
where x.No = 1;

An alternative would be to use a common table expression (CTE) instead of a subquery to isolate the first result set.

with x as
(
  select mt.ID,
         mt.CName,
         mt.Tot_Val,
         mt.PName,
         row_number() over(partition by mt.CName order by mt.Tot_Val desc) as No
  from MyTable mt
)
select x.*
from x
where x.No = 1;

See both solutions in action in this fiddle .

You can search top-n-per-group for this kind of a query.

There are two common ways to do it. The most efficient method depends on your indexes and data distribution and whether you already have another table with the list of all CName values.

  1. Using ROW_NUMBER
WITH
CTE
AS
(
    SELECT
        ID, CName, Tot_Val, PName,
        ROW_NUMBER() OVER (PARTITION BY CName ORDER BY Tot_Val DESC) AS rn
    FROM table1
)
SELECT
    ID, CName, Tot_Val, PName
FROM CTE
WHERE rn=1
;
  1. Using CROSS APPLY
WITH
CTE
AS
(
    SELECT CName
    FROM table1
    GROUP BY CName
)
SELECT
    A.ID
    ,A.CName
    ,A.Tot_Val
    ,A.PName
FROM 
    CTE
    CROSS APPLY
    (
        SELECT TOP(1)
            table1.ID
            ,table1.CName
            ,table1.Tot_Val
            ,table1.PName
        FROM table1
        WHERE
            table1.CName = CTE.CName
       ORDER BY
            table1.Tot_Val DESC
    ) AS A
;

See a very detailed answer on dba.se Retrieving n rows per group , or here Get top 1 row of each group .

CROSS APPLY might be as fast as a correlated subquery, but this often has very good performance (and better than ROW_NUMBER() :

select t.*
from t
where t.tot_val = (select max(t2.tot_val)
                   from t t2
                   where t2.cname = t.cname
                  );

Note: The performance depends on having an index on (cname, tot_val) .

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