我正在创建一份报告,比较不同单位的总时间和数量。这里简化了我目前正在使用的查询:
SELECT m.Unit,
COUNT(*) AS Count,
SUM(m.TimeInMinutes) AS TotalTime
FROM main_table m
WHERE m.unit <> ''
AND m.TimeInMinutes > 0
GROUP BY m.Unit
HAVING COUNT(*) > 15
然而,我被告知我需要排除行的时间最高或最低5%的情况,以试图摆脱一些古怪的异常值。 (如在应用聚合之前删除行。)
我该怎么做?
答案 0 :(得分:9)
您可以使用NTILE
排除上下x百分位数SELECT m.Unit,
COUNT(*) AS Count,
SUM(m.TimeInMinutes) AS TotalTime
FROM
(SELECT
m.Unit,
NTILE(20) OVER (ORDER BY m.TimeInMinutes) AS Buckets
FROM
main_table m
WHERE
m.unit <> '' AND m.TimeInMinutes > 0
) m
WHERE
Buckets BETWEEN 2 AND 19
GROUP BY m.Unit
HAVING COUNT(*) > 15
编辑:此article也有几种技术
答案 1 :(得分:2)
一种方法是使用not in
子句排除异常值:
where m.ID not in
(
select top 5 percent ID
from main_table
order by
TimeInMinutes desc
)
最后5%的另一个not in
条款。
答案 2 :(得分:2)
NTile非常不精确。如果您针对下面的示例视图运行NTile,您将看到它从中心捕获一些不确定的行数而不是90%。建议使用TOP 95%,然后反转TOP 90%几乎是正确的,除了90%x 95%只给出原始数据集的85.5%。所以你必须这样做
select top 94.7368 percent *
from (
select top 95 percent *
from
order by .. ASC
) X
order by .. DESC
首先创建一个与您的表列名匹配的视图
create view main_table
as
select type unit, number as timeinminutes from master..spt_values
试试这个
select Unit, COUNT(*), SUM(TimeInMinutes)
FROM
(
select *,
ROW_NUMBER() over (order by TimeInMinutes) rn,
COUNT(*) over () countRows
from main_table
) N -- Numbered
where rn between countRows * 0.05 and countRows * 0.95
group by Unit, N.countRows * 0.05, N.countRows * 0.95
having count(*) > 20
在删除异常值后,HAVING子句将应用于剩余的集合。 对于1,1,1,1,1,1,2,5,6,19的数据集,使用ROW_NUMBER可以正确地删除1的一个实例。
答案 3 :(得分:0)
我认为最强大的方法是将列表按顺序排序,然后排除顶部和底部的极值。对于一百个值,您将按升序排序并取第一个95 PERCENT,然后按降序排序并取第一个90 PERCENT。