簡體   English   中英

我如何獲得每個類別的前n條記錄

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM