如何从每组中选择TOP 5 PERCENT?

Leg*_*end 12 sql t-sql sql-server sql-server-2008 greatest-n-per-group

我有一个这样的样本表:

CREATE TABLE #TEMP(Category VARCHAR(100), Name VARCHAR(100))

INSERT INTO #TEMP VALUES('A', 'John')
INSERT INTO #TEMP VALUES('A', 'John')
INSERT INTO #TEMP VALUES('A', 'John')
INSERT INTO #TEMP VALUES('A', 'John')
INSERT INTO #TEMP VALUES('A', 'John')
INSERT INTO #TEMP VALUES('A', 'John')
INSERT INTO #TEMP VALUES('A', 'Adam')
INSERT INTO #TEMP VALUES('A', 'Adam')
INSERT INTO #TEMP VALUES('A', 'Adam')
INSERT INTO #TEMP VALUES('A', 'Adam')
INSERT INTO #TEMP VALUES('A', 'Lisa')
INSERT INTO #TEMP VALUES('A', 'Lisa')
INSERT INTO #TEMP VALUES('A', 'Bucky')
INSERT INTO #TEMP VALUES('B', 'Lily')
INSERT INTO #TEMP VALUES('B', 'Lily')
INSERT INTO #TEMP VALUES('B', 'Lily')
INSERT INTO #TEMP VALUES('B', 'Lily')
INSERT INTO #TEMP VALUES('B', 'Lily')
INSERT INTO #TEMP VALUES('B', 'Tom')
INSERT INTO #TEMP VALUES('B', 'Tom')
INSERT INTO #TEMP VALUES('B', 'Tom')
INSERT INTO #TEMP VALUES('B', 'Tom')
INSERT INTO #TEMP VALUES('B', 'Ross')
INSERT INTO #TEMP VALUES('B', 'Ross')
INSERT INTO #TEMP VALUES('B', 'Ross')

SELECT Category, Name, COUNT(Name) Total
FROM #TEMP
GROUP BY Category, Name
ORDER BY Category, Total DESC

DROP TABLE #TEMP
Run Code Online (Sandbox Code Playgroud)

给我以下内容:

A   John    6
A   Adam    4
A   Lisa    2
A   Bucky   1
B   Lily    5
B   Tom     4
B   Ross    3
Run Code Online (Sandbox Code Playgroud)

现在,我该如何选择TOP 5 PERCENT从每个类别记录假设每个类别都有超过100条记录(未在样本表显示这里)?举例来说,在我实际的表,它应该删除John从记录ALily从唱片B(再说一次,我没有表现出全表这里)酌情获得:

A   Adam    4
A   Lisa    2
A   Bucky   1
B   Tom     4
B   Ross    3
Run Code Online (Sandbox Code Playgroud)

我一直在尝试使用CTEs和PARTITION BY子句,但似乎无法实现我想要的.它从总体结果中删除了TOP 5 PERCENT,但不从每个类别中删除.有什么建议?

mar*_*c_s 17

您可以使用与NTILE窗口函数配对的CTE(公用表表达式)- 这会将您的数据切片为您需要的多个切片,例如在您的情况下,切成20个切片(每个5%).

;WITH SlicedData AS
(
   SELECT Category, Name, COUNT(Name) Total,
            NTILE(20) OVER(PARTITION BY Category ORDER BY COUNT(Name) DESC) AS  'NTile'
   FROM #TEMP
   GROUP BY Category, Name
)
SELECT *
FROM SlicedData
WHERE NTile > 1
Run Code Online (Sandbox Code Playgroud)

这基本上将您的数据分组Category,Name,按其他方式排序(不确定是否COUNT(Name)真的是您想要的东西),然后将其分成20个部分,每个部分代表5%的数据分区.切片NTile = 1是最高的5%切片 - 从CTE中选择时忽略它.

看到:

了解更多信息

  • 这符合我的目的。太感谢了。我修复了您的帖子中查询中缺少的一些部分,使其开箱即用。 (2认同)