使用前x个产品选择前x个类别

时间:2015-04-12 16:33:26

标签: sql sql-server

我有以下查询,它选择每个类别的前3个记录。目前它将记录限制为9.但是,这不正确,因为如果我将数字限制为8,则最后一个子类别会从显示中丢失一条记录。

我想限制每个SubCategories查询号码的记录,即仅限3个子类别的前3个产品。

我所拥有的是以下内容:

SELECT TOP 9 *
FROM tProduct p
WHERE p.ProductID IN (
    SELECT TOP 3 ProductID
    FROM tProduct PP
    WHERE pp.SubCategoryID = p.SubCategoryID 
    )
ORDER BY SubCategoryID

任何想法如何修改上述内容?

编辑:根据建议CROSS APPLY,我到目前为止最接近的是:

SELECT * FROM tSubCategory c
CROSS APPLY
(
    SELECT TOP(3) *

    FROM tProduct p
    WHERE
        c.SubCategoryID = p.SubCategoryID
    ORDER BY
        p.ProductID DESC
) x
WHERE c.SubCategoryID BETWEEN 1 AND 2;

但是,查询应仅指定一个数字,即4个类别,而不是1到2之间的数据,这些数字适用于子类别ID。

4 个答案:

答案 0 :(得分:1)

这看起来就像Rob Farley在这里提到的CROSS APPLY的一个例子: http://blogs.lobsterpot.com.au/2011/04/13/the-power-of-t-sqls-apply-operator/

对于此特定查询,您需要选择前3个子类别行,然后使用OUTER APPLY将其附加到每个产品行。然而,您将无法在选择中使用前9,因为这将仅占用9行(而不是前9个产品ID)。这需要使用WHERE子句来完成。下面的查询(带有一些列名修改)应该可以解决问题:

SELECT *
FROM Product AS p
OUTER APPLY ( 
    SELECT TOP (3) s.description 
    FROM SubCategory AS s
    WHERE s.ID = p.subcategoryId 
    GROUP BY s.id, s.description 
    ORDER BY s.id DESC) as s 
  WHERE p.Id IN (select distinct top 9 Id from Product);   

答案 1 :(得分:1)

你的意思是:

SELECT * FROM 
(SELECT TOP(3) * FROM tSubCategory) c
CROSS APPLY
(
    SELECT TOP(3) *
    FROM tProduct p
    WHERE c.SubCategoryID = p.SubCategoryID
    ORDER BY p.ProductID DESC
) x;

...我所基于的只是将你的tSubCategory包装到一个子查询中,将它限制为只有三行。

答案 2 :(得分:0)

使用窗口功能。我不确定你想要什么输出,但以下内容应该非常接近:

SELECT p.*
FROM (SELECT p.*,
             row_number() over (partition by ProductId order by SubCategoryId) as sc_seqnum,
             dense_rank() over (order by ProductId) as p_seqnum
      FROM tProduct p
     ) p
WHERE sc_seqnum <= 3 and -- number of subcategories per product 
      p_seqnum <= 3  -- number of products to show

答案 3 :(得分:0)

如果我理解正确,这是使用CROSS APPLY的完美案例。

在这里阅读更多:
http://www.codeproject.com/Articles/607246/Making-OUTER-and-CROSS-APPLY-work-for-you

请看第一个用例。