如何在 SQL Server 2012 的列中查找最大值

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

我想在一列中找到最大值

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

以上是我的table结构。我只想从 table 中找到最大总值。这四行 ID 1 和 2 在 CName 中具有相同的值,但 total val 和 PName 具有不同的值。我期望的是必须在 ID 1 和 2

中找到最大值

预期结果:

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

我需要与上述相同的结果

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

这是我试过的查询,但我的问题是我无法在此 table 中引入 PName。如果我在 select 列表中添加 PName 意味着它将显示加倍的行,例如结果是 100 行,但是当我在 selected 列表中添加 PName 并按列表分组时,它显示 600 行。就是这个问题。

谁能帮我解决这个问题。

一个可能的选择是使用子查询。在按 Tot_Val 排序的每个 CName 组中为每一行指定一个数字。然后select行号等于1的行。

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;

另一种方法是使用通用 table 表达式 (CTE) 而不是子查询来隔离第一个结果集。

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;

this fiddle 中查看两种解决方案的实际应用。

您可以在 top-n-per-group 中搜索此类查询。

有两种常用的方法。最有效的方法取决于您的索引和数据分布,以及您是否已经有另一个 table 和所有 CName 值的列表。

  1. 使用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. 使用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
;

查看关于 dba.se Retrieving n rows per group 的非常详细的答案 ,或此处 获取每组的前 1 行 .

CROSS APPLY 可能与相关子查询一样快,但这通常具有非常好的性能(并且优于 ROW_NUMBER():

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

注意:性能取决于 (cname, tot_val) 上的索引。