每组生成 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
已知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