[英]How do i get top n records of each category
我在這里是根據類別獲取記錄。
我的表foo具有字段[id,name,class] 。 我的記錄可以像:
1, ram, 10
2, hari, 9
3, sita, 10
4, gita, 9
5, rita, 5
6, tina, 7
8, nita, 8
9, bita, 5
10,seta, 7
...和更多...
現在我想從不同類的每條記錄中獲取結果。
1, ram, 10
2, hari, 9
5, rita, 5
6, tina, 7
8, nita, 8
即每個類別的前1個記錄
對於SQL Server 2005+和Oracle 9i +,請使用分析功能:
WITH summary AS (
SELECT f.id,
f.name,
f.class,
ROW_NUMBER() OVER (PARTITION BY f.class
ORDER BY f.name) AS rank
FROM FOO f)
SELECT s.id,
s.name,
s.class
FROM summary s
WHERE s.rank = 1
這也使用通用表表達式(CTE),在Oracle中稱為子查詢分解。
MySQL不支持分析功能,因此您必須使用:
SELECT x.id,
x.name,
x.class
FROM (SELECT f.id,
f.name,
f.class,
CASE
WHEN @class = f.class THEN @rownum := @rownum + 1
ELSE @rownum := 1
END AS rank,
@class := f.class
FROM FOO f
JOIN (SELECT @rownum := 0, @class := '') r
ORDER BY f.class, f.name) x
WHERE x.rank = 1
這應該是最簡單的方法,它不涉及任何特定於數據庫的選項:
select *
from foo
where id in (select min(id)
from foo
group by class);
upd:是的,只有在每個班級只需要一條記錄的情況下,這才有效。
upd2:只是為了好玩而提出一個查詢,它向您顯示TOP N,並且不涉及分析。 看起來有點混亂,但似乎可以工作:)
select newfoo.id, newfoo.name, newfoo.class
from (select class, max(r) top, min(r) bottom
from (select f.*, rownum r
from (select id, name, class from foo order by class, id asc) f)
group by class) minmax,
(select id, name, class, r
from (select f.*, rownum r
from (select id, name, class from foo order by class, id asc) f)) newfoo
where newfoo.class = minmax.class
and newfoo.r between minmax.bottom and
least(minmax.bottom + (TOP_N-1), minmax.top);
其中TOP_N
是您需要獲取的記錄數量。
我在sql 2008中對此進行了測試,並為我工作,希望能以某種方式對您有所幫助。
DECLARE @Class TABLE
(
id INT
,Name NVARCHAR(120)
,Class INT
PRIMARY KEY (id)
)
INSERT INTO @Class values (1, 'ram', 10)
INSERT INTO @Class values (2, 'hari', 9)
INSERT INTO @Class values (3, 'sita', 10)
INSERT INTO @Class values (4, 'gita', 9)
INSERT INTO @Class values (5, 'rita', 5)
INSERT INTO @Class values (6, 'tina', 7)
INSERT INTO @Class values (8, 'nita', 8)
INSERT INTO @Class values (9, 'bita', 5)
INSERT INTO @Class values (10, 'seta', 7)
SELECT A.id, A.Name, A.Class
FROM
(
SELECT ROW_NUMBER() OVER (PARTITION BY Class ORDER BY ID) as Num, ID, Name, Class
FROM @Class
) A
WHERE A.Num = 1
ORDER BY id
使用SQL Server或Oracle(或實現該標准的該部分的任何其他引擎,包括PostgreSQL等免費引擎), OVER
子句中的“窗口函數”(例如,有關MS的文檔,請參見此處 )變得容易; 例如,在此SO問題中 ,請參閱@Darrel的答案(他正在選擇每個類別的前10個,只希望前1個,更改應該很明顯;-)。
在MySql或其他不符合OVER
子句標准的引擎中,您可以使用@Bill的答案(對MySql有用,對其他用戶則不行)或@Matt的答案(由於他為SQL Server回答,因此可能需要稍作修改,因此請使用SELECT TOP 10 ...
在MySql中為SELECT ... LIMIT 10
!-)。
這是另一種方式
DECLARE @foo TABLE(ID INT,Name VARCHAR(20),Class INT)
INSERT INTO @foo
SELECT 1,'ram', 10 UNION ALL
SELECT 2, 'hari', 9 UNION ALL
SELECT 3, 'sita', 10 UNION ALL
SELECT 4, 'gita', 9 UNION ALL
SELECT 5, 'rita', 5 UNION ALL
SELECT 6, 'tina', 7 UNION ALL
SELECT 8, 'nita', 8 UNION ALL
SELECT 9, 'bita', 5 UNION ALL
SELECT 10,'seta', 7
SELECT DISTINCT X.*
FROM @foo f
CROSS APPLY(SELECT TOP 1 * FROM @foo WHERE Class = f.Class) AS X
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.