Amazon RedShift sql: удалить верхние 1% данных как выбросы

Я пытаюсь удалить 1% данных, поскольку мы рассматриваем те выбросы, которые сильно искажают данные. я пытался использовать SELECT TOP 99 PERC, но Amazon Redshift не поддерживает проценты с TOP.

Я пробовал что-то вроде:

WITH 
elapsed_times AS (
  SELECT 
    COALESCE(anonymous_id, distinct_id) as id,
    elapsed_time
  FROM studio_production.interaction
  WHERE project_id = '55062b464a9bc578006987ff'
),
max_elapsed_time AS (
  SELECT elapsed_time
  FROM elapsed_times
  ORDER BY elapsed_time ASC
  OFFSET ROUND(0.99 * (SELECT COUNT(*) FROM elapsed_times))
  LIMIT 1
),
user_times AS (
  SELECT 
    id, 
    LEAST(elapsed_time, max_elapsed_time) as elapsed_time
  FROM elapsed_times
  GROUP BY 1
)

SELECT AVG(elapsed_time) FROM user_times

Но я получаю: argument of OFFSET must not contain subqueries

Таким образом, мой запрос сейчас:

WITH 
elapsed_times AS (
  SELECT 
    COALESCE(anonymous_id, distinct_id) as id,
    elapsed_time,
    RANK() OVER (ORDER BY elapsed_time ASC) as rnk
  FROM studio_production.interaction
  WHERE project_id = '55062b464a9bc578006987ff'
), 
user_times AS (
  SELECT 
    id,
    LEAST(MAX(elapsed_time), (
      SELECT MIN(elapsed_time)
      FROM elapsed_times
      WHERE rnk > ROUND(0.99 * (SELECT COUNT(*) FROM elapsed_times))
    )) as elapsed_time
  FROM elapsed_times
  GROUP BY 1
)

SELECT AVG(elapsed_time) FROM user_times

что на самом деле довольно медленно. как правильно подойти к этой проблеме?

1 ответ

Вы могли бы использовать ntile() (см. здесь):

select avg(elapsed_time)
from (select et.*,
             ntile(100) over (order by elapsed_time) as thetile
      from elapsed_times et
     ) et
where thetile not in (1, 100);

РЕДАКТИРОВАТЬ:

Я признаю, что я часто делаю это, используя row_number() а также count():

select avg(elapsed_time)
from (select et.*,
             row_number() over (order by elapsed_time) as seqnum,
             count(*) over () as cnt
      from elapsed_times et
     ) et
where (seqnum <= 0.01 * cnt) or (seqnum >= 0.99 * cnt);
Другие вопросы по тегам