每组生成 n 行

Producing n rows per group

已知GROUP BY每组产生一行。我想每组生成多行。例如,特定用例是为每个项目选择两个最便宜的产品。

组中的两个或三个元素是微不足道的:

select type, variety, price
from fruits
where price = (select min(price) from fruits as f where f.type = fruits.type)
   or price = (select min(price) from fruits as f where f.type = fruits.type
      and price > (select min(price) from fruits as f2 where f2.type = fruits.type));

(Select n rows per group in mysql)

但我正在寻找一个可以显示每组 n 行的查询,其中 n 是任意大的。换句话说,每组显示 5 行的查询应该可以转换为每组显示 7 行的查询,只需替换其中的一些常量即可。

我不受任何 DBMS 的限制,所以我对在任何 DBMS 上运行的任何解决方案都感兴趣。如果它使用一些非标准语法也没关系。

对于任何支持解析函数\window函数的数据库,这都比较容易

select *
  from (select type, 
               variety, 
               price,
               rank() over ([partition by something]
                            order by price) rnk
          from fruits) rank_subquery
 where rnk <= 3

如果您省略 [partition by something],您将获得前三行。如果你想要每个 type 的前三名,你会在你的 rank() 函数中 partition by type

根据您希望如何处理平局,您可能希望使用 dense_rank()row_number() 而不是 rank()。如果两行并列第一,使用 rank,下一行的 rnk 为 3,而下一行的 rnk 为 2,使用 dense_rank。在这两种情况下,两个并列行的 rnk 都为 1。row_number 会任意给两个并列行中的一个 rnk 为 1,另一个 rnk 为2.

"greatest N per group problems" 可以使用 window 函数轻松解决:

select type, variety, price
from (
  select type, variety, price,
         dense_rank() over (partition by type) order by price as rnk
  from fruits
) t
where rnk <= 5;

为了节省任何人的时间,在撰写本文时,显然这行不通,因为 https://dev.mysql.com/doc/refman/5.7/en/subquery-restrictions.html

我从来都不是相关子查询的粉丝,因为我看到它们的大多数用途通常可以写得更简单,但我认为这已经改变了……一点点。 (这是为了 MySQL。)

SELECT `type`, `variety`, `price`
FROM `fruits` AS f2
WHERE `price` IN (
   SELECT DISTINCT `price` 
   FROM `fruits` AS f1 
   WHERE f1.type = f2.type
   ORDER BY `price` ASC
   LIMIT X
   )
;

其中 X 是您想要的 "arbitrary" 值。

如果您知道如何在重复价格的情况下进一步限制,并且数据允许这样的限制...

SELECT `type`, `variety`, `price`
FROM `fruits` AS f2
WHERE (`price`, `other_identifying_criteria`) IN (
   SELECT DISTINCT `price`, `other_identifying_criteria`
   FROM `fruits` AS f1 
   WHERE f1.type = f2.type
   ORDER BY `price` ASC, `other_identifying_criteria` [ASC|DESC]
   LIMIT X
   )
;

Windows 函数仅适用于 SQL Server 2012 及更高版本。试试这个:

SQL Server 2005 及以上解决方案

DECLARE @yourTable TABLE(Category VARCHAR(50), SubCategory VARCHAR(50), price INT)
INSERT INTO @yourTable
VALUES  ('Meat','Steak',1),
        ('Meat','Chicken Wings',3),
        ('Meat','Lamb Chops',5);

DECLARE @n INT = 2;

SELECT DISTINCT Category,CA.SubCategory,CA.price
FROM @yourTable A
CROSS APPLY
(
    SELECT TOP (@n) SubCategory,price
    FROM @yourTable B
    WHERE A.Category = B.Category
    ORDER BY price DESC
) CA

每个类别中两个价格最高的子类别的结果:

Category                  SubCategory               price
------------------------- ------------------------- -----------
Meat                      Chicken Wings             3
Meat                      Lamb Chops                5