SQL-select每个组WITH CONDITION的前3个值

时间:2013-11-02 00:02:27

标签: sql sql-server greatest-n-per-group

我想为每个标签提取不同产品类别的前三大畅销产品。 数据如下所示:

tag  | product_name | product_category | order_count
tag1 | product1     | category1        | 100
tag1 | product2     | category2        | 80
tag1 | product3     | category2        | 60
tag1 | product4     | category3        | 50
......

我知道如何使用ROW_NUMBER()为每个标签提取前3个销售产品,但它会返回product1,product2,product3。我不想要product3,因为它与product2属于同一类别。我想要product4。如何在SQL Server中执行此操作?

3 个答案:

答案 0 :(得分:4)

首先ROW_NUMBER删除每个标记和product_category的重复行,第二个ROW_NUMBER为每个标记选择前3个销售产品

;WITH cte AS
 (SELECT *, ROW_NUMBER() OVER(PARTITION BY tag, product_category ORDER BY order_count DESC) AS rn
  FROM yourtable
  ), cte2 AS
  (SELECT *, ROW_NUMBER() OVER(PARTITION BY tag ORDER BY order_count DESC) AS rn2
   FROM cte
   WHERE rn = 1
   )
   SELECT *
   FROM cte2
   WHERE rn2 <= 3

SQLFiddle上的演示

下一个使用派生表

;WITH cte AS
 (SELECT t2.tag, t2.product_name, t2.product_category, t2.order_count,
         ROW_NUMBER() OVER(PARTITION BY t2.tag ORDER BY order_count DESC) AS rn
  FROM (SELECT tag, product_category, MAX(order_count) AS maxCount
        FROM yourtable
        GROUP BY tag, product_category
        ) t1 JOIN yourtable t2 ON t1.tag = t2.tag 
          AND t1.product_category = t2.product_category
          AND maxCount = order_count
  )
  SELECT *
  FROM cte
  WHERE rn <= 3

SQLFiddle上的演示

答案 1 :(得分:3)

只要您使用RANK(),就可以使用ROW_NUMBER()(或PARTITION BY)。假设您正在使用SQL Server 2005 +:

,这与TOP()结合应该可以正常工作
with cte as (
  select tag, 
    product_name, 
    product_category, 
    order_count, 
    rank() over (partition by product_category 
                 order by product_category, order_count desc) rnk
  from yourtable
  )
select top 3 tag, product_name, product_category, order_count
from cte 
where rnk = 1
order by order_count desc

这将产生以下结果:

TAG     PRODUCT_NAME   PRODUCT_CATEGORY  ORDER_COUNT
tag1    product1       category1         100
tag1    product2       category2         80
tag1    product4       category3         50

答案 2 :(得分:0)

我建议只使用一个选择

declare @t table (
    tag                 varchar(10),
    product_name        varchar(10),
    product_category    varchar(10),
    order_count         int
);

insert into @t values
('tag1', 'product1', 'category1', 100),
('tag1', 'product2', 'category2', 80 ),
('tag1', 'product3', 'category2', 60 ),
('tag1', 'product4', 'category3', 50 ),
('tag1', 'product5', 'category4', 40 );


select top 3
    *
from
    @t
order by
    row_number() over(partition by product_category order by order_count desc), 
    order_count desc;

SQL Fiddle