Вы можете рассмотреть возможность использования оконной функции, такой как OVER / PARTITION BY. Это позволит вам точно настроить исключения в определенных группах строк (например, по имени, дате или часу). В этом примере я позаимствовал строки из примера t-clausen.dk и расширил их, добавив имя, чтобы мы могли продемонстрировать управление окнами.
-- Set boundaries, like the TOP PERCENT used in the afore mentioned example
DECLARE @UBOUND FLOAT, @LBOUND FLOAT</p>
<p>SET @UBOUND = 0.8 --(80%)
SET @LBOUND = 0.2 --(20%)</p>
<p>--Build a CTE table
;WITH tb_example AS (
select [Val]=21,[fname]='Bill' union all
select 54,'Tom' union all
select 34,'Tom' union all
select 14,'Bill' union all
select 20,'Bill' union all
select 300,'Tom' union all
select 23,'Bill' union all
select 1,'Tom' union all
select 1,'Tom' union all
select 1,'Bill' union all
select 1,'Tom' union all
select 200,'Bill' union all
select 1,'Tom' union all
select 12,'Tom' union all
select 8,'Tom' union all
select 11,'Bill' union all
select 100,'Bill'
)</p>
<p>--Outer query applies criteria of your choice to remove spikes
SELECT fname,AVG(Val) FROM (
-- Inner query applies windowed aggregate values for outer query processing
SELECT *
,ROW_NUMBER() OVER (PARTITION BY fname order by Val) RowNum
,COUNT(*) OVER (PARTITION BY fname) RowCnt
,MAX(Val) OVER (PARTITION BY fname) MaxVal
,MIN(Val) OVER (PARTITION BY fname) MinVal
FROM tb_example
) TB
WHERE
-- You can use the bounds to eliminate the top and bottom 20%
RowNum BETWEEN (RowCnt*@LBOUND) and (RowCnt*@UBOUND) -- Limits window
-- Or you may chose to simply eliminate the Max and MIN values
OR (Val > MinVal AND Val < MaxVal) -- Removes Lowest and Highest values
GROUP BY fname
В этом случае я использую оба критерия и AVG val по fname. Но небо - это предел того, как вы решили смягчать пики с помощью этой техники.