以前在開發的時候遇到過一個需求,就是要按照某一列進行分組后取前幾條數據,今天又有同事碰到了,幫解決了之后順便寫一篇博客記錄一下。
首先先建一個基礎數據表,代碼如下:
IF OBJECT_ID(N'Test') IS NOT NULL
BEGIN
DROP TABLE Test
ENDCREATE TABLE Test(
ID bigint IDENTITY(1,1),
Name nvarchar(50),
Department nvarchar(50))
INSERT INTO Test(Name,Department)
VALUES('張三','行政'),
('李四','運營'),
('王五','行政'),
('趙六','研發'),
('錢七','工程'),
('Amy','研發'),
('Tomy','工程'),
('Tony','研發'),
('Tom','工程'),
('Alice','行政'),
('Mary','行政'),
('Elaine','運營'),
('Geno','行政'),
('Gary','工程')
GO
建好后,這張表的數據如下:
現在的需求是按照Department列進行分組,按ID取每個部門前2條記錄,只寫一條SQL語句的話,分別可以用3種方法實現,代碼如下:
SELECT ID,Name,Department FROM
(SELECT nn=ROW_NUMBER() OVER(PARTITION BY Department ORDER BY ID),* FROM Test) b WHERE nn<=2
SELECT * FROM Test t WHERE
(SELECT COUNT(*) FROM Test WHERE Department=t.Department AND ID<=t.ID)<=2 ORDER BY Department
SELECT * FROM Test t
WHERE ID in (SELECT DISTINCT TOP 2 ID FROM Test WHERE Department=t.Department)
ORDER BY Department
第一種方法使用了ROW_NUMBER()函數,這個函數是在SQL 2005及以上版本才有的,所以如果數據庫是2000的話只能用下面兩種方法,運行之后得到的結果都一樣,如下圖:
總結,碰到此類需求可以直接用下面代碼進行套用:
SELECT 要輸出的列,除nn外 FROM
(SELECT nn=ROW_NUMBER() OVER(PARTITION BY 分組的列 ORDER BY 排序的列),* FROM 表名) b WHERE nn<=前N條數據
SELECT * FROM 表名 t WHERE
(SELECT COUNT(*) FROM 表名 WHERE 分組的列=t.分組的列 AND 排序的列<=t.排序的列)<=前N條數據 ORDER BY 分組的列
SELECT * FROM 表名 t
WHERE 排序的列 in (SELECT DISTINCT TOP 前N條數據 排序的列 FROM 表名 WHERE 分組的列=t.分組的列)
ORDER BY 分組的列