使用max和其他SQL聚合函数

时间:2014-07-31 14:55:41

标签: sql sql-server aggregate-functions

每当我使用SQL聚合函数时,我发现它们的实用程序因Group By子句的需要而受到阻碍。我总是不得不使用一堆嵌套选择来获得我想要的东西。我想知道我是不是没有正确使用这些功能。

例如。如果我有以下数据:

ID     Fruit     Color     CreatedDate
--     -----     -----     -----------
1      Apple      Red      2014-07-25 12:41:44.000
2      Apple      Green    2014-07-31 10:01:01.000
3      Apple      Blue     2014-07-10 07:05:51.317
4      Orange     Orange   2014-06-26 13:42:35.360

我想获得最近创建的苹果记录。如果我用这个:

SELECT [ID]
      ,[Fruit]
      ,[Color]
      ,max([CreatedDate])
  FROM [CCM].[dbo].[tblFruit]
  WHERE Fruit = 'Apple'
  GROUP BY ID, Fruit, Color

它给了我所有三个Apple条目,而不仅仅是最新条目,因为我被迫在group by子句中包含所有其他列。真的,我只是希望它按水果分组并给我最新记录(整个记录,而不仅仅是列的一部分)。

为了得到我想要的东西,我必须使用它:

SELECT [ID]
      ,[Fruit]
      ,[Color]
      ,[CreatedDate]
  FROM [CCM].[dbo].[tblFruit]
  WHERE Fruit = 'Apple' AND CreatedDate IN
  (SELECT max([CreatedDate]) as [CreatedDate]
  FROM [CCM].[dbo].[tblFruit]
  WHERE Fruit = 'Apple')

这对我来说很丑陋,在SQL中忘记聚合并在.NET中执行任何min,max,count等会更容易。

这是使用聚合的正确方法(使用嵌套选择)还是我做错了?

3 个答案:

答案 0 :(得分:3)

对于这种情况,您最好使用像row_number()

这样的窗口函数
select id, fruit, color, createddate
from 
(
  select id, fruit, color, createddate,
    row_number() over(partition by fruit order by createddate desc) seq
  from tblFruit
) d
where seq = 1;

请参阅Demo

使用此功能,您可以按fruit对数据进行分区,并按fruit对每个createddate内的行进行排序。通过将row_number()放在子查询中,您将返回每个fruit的第一行 - 这些是带有seq=1的项目。如果您要查找仅Apple的项目,则可以轻松添加WHERE子句。

您还可以使用子查询为每个max(createddate)选择fruit来获得结果:

select f.id,
  f.fruit,
  f.color,
  f.createddate
from tblFruit f
inner join
(
  select fruit, max(createddate) CreatedDate
  from tblfruit
  group by fruit
) d
  on f.fruit = d.fruit
  and f.createddate = d.createddate;

Demo。您得到相同的结果,但仍然可以对此应用WHERE过滤器。

答案 1 :(得分:0)

根据您的评论,您可以使用CTE来构建每个水果的最大日期列表。然后,您可以将其加入到原始表中,以获得与该最大日期匹配的完整行。

SQL Fiddle

    with MaxDates as 
    (select 
     fruit,
     max(createddate) as maxdate
     from
     table1
     group by
     fruit)

    select
    t1.*
    from
    table1 t1
    inner join maxdates md
      on t1.fruit = md.fruit

  and t1.createddate = md.maxdate
顺便说一下,你真的不想尝试将这种功能推向你的应用程序。在SQL中做这种事情是无限好的。如果没有别的,请考虑一下你的表中是否有数百万行。您当然不希望将数百万行从数据库中推送到应用程序,以将其总计为单行等。

答案 2 :(得分:0)

如何将TOP与ORDER BY一起使用

SELECT TOP(1) *
  FROM [CCM].[dbo].[tblFruit]
  WHERE Fruit = 'Apple'
  ORDER BY [CreatedDate] DESC