查询以查找组中的第一个和第二个最大值

时间:2010-12-14 15:13:52

标签: sql sql-server-2008

我有这样的查询:

SELECT
 DATEPART(year,some_date),
 DATEPART(month,some_date),
 MAX(some_value) max_value
FROM
 some_table
GROUP BY
    DATEPART(year,some_date),
    DATEPART(month,some_date)

这将返回一个表格,其中包含:年,月,该月份的最大值

我想修改查询,以便我可以获得: 年,月,本月最大值,每月第二大值

在我看来,众所周知的解决方案,如“TOP 2”,“NOT IN TOP IN”或subselect将不适用于此。

(非常具体 - 我正在使用SQL Server 2008.)

感谢任何帮助,thx。

6 个答案:

答案 0 :(得分:3)

RANK()可能是您正在寻找的东西......

http://msdn.microsoft.com/en-us/library/ms176102.aspx

答案 1 :(得分:3)

在我看来,这个问题需要一个最佳的查询,并且每个月和每年在同一行中排名第二,如下所示:

month, year, best, second best
...
...

而不是包含最佳和第二最佳值的同一个月和每年的两行。

这是我提出的解决方案,所以如果有人有更简单的方法来实现这一点,我想知道。

with ranks as (
    select 
        year(entrydate) as [year], 
        month(entrydate) as [month], 
        views, 
        rank() over (partition by year(entrydate), month(entrydate) order by views desc) as [rank]
    from product
)
select 
    t1.year, 
    t1.month, 
    t1.views as [best], 
    t2.views as [second best]
from ranks t1
    inner join ranks t2
        on t1.year = t2.year
        and t1.month = t2.month
        and t1.rank = 1
        and t2.rank = 2
编辑:出于好奇,我做了一些测试,最后在Stephanie Page's answer上使用了一个更简单的变体而没有使用aditional子查询。我将rank()函数更改为row_number(),因为当两个最大值相同时它不起作用。

with ranks as (
    select 
        year(entrydate) as [year], 
        month(entrydate) as [month], 
        views, 
        row_number() over (partition by year(entrydate), month(entrydate) order by views desc) as [rank]
    from product
)
select 
    t1.year, 
    t1.month, 
    max(case when t1.rank = 1 then t1.views else 0 end) as [best], 
    max(case when t1.rank = 2 then t1.views else 0 end) as [second best]
from 
    ranks t1
where
    t1.rank in (1,2)
group by
    t1.year, t1.month

答案 2 :(得分:2)

在没有连接的情况下执行此操作(我将显示Oracle ...您将只使用CASE而不是DECODES)

with ranks as (
        select 
            year(entrydate) as [year], 
            month(entrydate) as [month], 
            views, 
            rank() over (partition by year(entrydate), month(entrydate) order by views desc) as [rank]
        from product
    )
SELECT [year], [month], Max([best]), Max([second best])
 FROM
    ( select 
        t1.year, 
        t1.month, 
        Decode([rank],1,t1.views,0) as [best], 
        Decode([rank],2,t1.views,0)  as [second best]
    from ranks t1
    where t1.rank <= 2 ) x
GROUP BY [year], [month]

答案 3 :(得分:1)

这是一个老派,但如果你使用ORDER BY,TOP和子查询将会起作用。试试这个:

SELECT TOP 2
 DATEPART(year,some_date),
 DATEPART(month,some_date),
 (SELECT MAX(st1.some_value) FROM some_table AS st1 
  WHERE DATEPART(month,some_date) = DATEPART(month,st1.some_date)) AS max_value
FROM
 some_table
GROUP BY
    DATEPART(year,some_date),
    DATEPART(month,some_date)
ORDER BY DATEPART(month,some_date) DESC

这将为您提供两行&#34;最高&#34;月份值和添加的子选择应该为每个分组提供最大值。

答案 4 :(得分:1)

您可以在SQL Server 2005及更高版本中使用具有排名功能的CTE:

;WITH TopValues AS
(
   SELECT
     YEAR(some_date) AS 'Year',
     MONTH(some_date) AS 'Month',
     Some_Value,
     ROW_NUMBER() OVER(PARTITION BY YEAR(some_date),MONTH(some_date) 
                       ORDER BY Some_Value DESC) AS 'RowNumber'
  FROM
     dbo.some_table
)
SELECT
    Year, Month, Some_Value
FROM
    TopValues
WHERE
    RowNumber <= 2

这将按月/年“分区”(即分组)您的数据,在每个组内按Some_Value降序排序(最大的第一个),然后您可以从该CTE中选择每组中的前两个。

RANK()同样适用(我经常使用ROW_NUMBER) - 它会产生稍微不同的结果 - 但实际上取决于您的需求。

答案 5 :(得分:0)

嗯,这是一种装备,但是你可以用子查询做到这一点......而不是使用那个max我会选择具有匹配年份和年份的some_values。 month,row_number()= 1 / row_number()= 2,并按some_value DESC排序。

无法在SQLite中使用OFFSET / LIMIT,这是我对SQL Server的不喜欢。