Oracle SQL для фильтрации High из нормальных значений - PullRequest
2 голосов
/ 15 апреля 2020

У меня есть пример данных, как показано ниже, и я хотел отфильтровать / определить из нормальных значений. Не уверен, как ИСКЛЮЧИТЬ значения OUTLIER в конструкции SQL. Пробовал брать среднее (Sal), но не уверен, как исключить эти высокие значения из среднего?

    date   dept_id  Sal
    201907   10     250
    201907   10     290
    201907   10     320
    201907   10     100000
    201907   10     500000
    201908   20     800
    201908   20     860
    201908   20     700
    201908   20     850000
    201908   20     1000000
    201909   10     260
    201909   10     230
    201909   10     310

Ожидаемый результат, как показано ниже

    date   dept_id  Sal     out_of_normal_values
    201907   10     250         N
    201907   10     290         N
    201907   10     320         N
    201907   10     100000      Y   
    201907   10     500000      Y
    201908   20     800         N 
    201908   20     860         N
    201908   20     700         N
    201908   20     850000      Y
    201908   20     1000000     Y
    201909   10     260         N
    201909   10     230         N
    201909   10     310         N

Ответы [ 3 ]

2 голосов
/ 15 апреля 2020

Вы можете создать оператор CASE следующим образом

case
    when
        sal > 1000
    then
        'Y'
    else
        'N'
end as out_of_normal_values
1 голос
/ 15 апреля 2020

Если вы хотите найти значения, которые находятся в пределах двух стандартных отклонений от среднего, тогда вы можете использовать функции analyti c (и избегать использования самосоединения):

SELECT dt,
       dept_id,
       sal,
       CASE
       WHEN sal BETWEEN avg_sal - 2 * stddev_sal
                AND     avg_sal + 2 * stddev_sal
       THEN 'N'
       ELSE 'Y'
       END AS out_of_normal_values
FROM   (
  SELECT t.*,
         AVG( sal ) OVER () AS avg_sal,
         STDDEV( sal ) OVER () AS stddev_sal
  FROM   table_name t
);

Какие для ваших данных:

CREATE TABLE  table_name ( dt, dept_id, Sal ) AS
SELECT 201907,   10,     250 FROM DUAL UNION ALL
SELECT 201907,   10,     290 FROM DUAL UNION ALL
SELECT 201907,   10,     320 FROM DUAL UNION ALL
SELECT 201907,   10,     100000 FROM DUAL UNION ALL
SELECT 201907,   10,     500000 FROM DUAL UNION ALL
SELECT 201908,   20,     800 FROM DUAL UNION ALL
SELECT 201908,   20,     860 FROM DUAL UNION ALL
SELECT 201908,   20,     700 FROM DUAL UNION ALL
SELECT 201908,   20,     850000 FROM DUAL UNION ALL
SELECT 201908,   20,     1000000 FROM DUAL UNION ALL
SELECT 201909,   10,     260 FROM DUAL UNION ALL
SELECT 201909,   10,     230 FROM DUAL UNION ALL
SELECT 201909,   10,     310 FROM DUAL;

Выходы:

    DT | DEPT_ID |     SAL | OUT_OF_NORMAL_VALUES
-----: | ------: | ------: | :-------------------
201907 |      10 |     250 | N                   
201907 |      10 |     290 | N                   
201907 |      10 |     320 | N                   
201907 |      10 |  100000 | N                   
201907 |      10 |  500000 | N                   
201908 |      20 |     800 | N                   
201908 |      20 |     860 | N                   
201908 |      20 |     700 | N                   
201908 |      20 |  850000 | N                   
201908 |      20 | 1000000 | Y                   
201909 |      10 |     260 | N                   
201909 |      10 |     230 | N                   
201909 |      10 |     310 | N                   

Что исключило самое экстремальное значение; если бы у вас был больший набор данных, то это, вероятно, было бы более эффективным, поскольку у вас будет большее соотношение «нормальных» значений к «выбросам». Однако, поскольку у вас небольшой набор данных с двумя широко разделенными пиками данных, среднее значение лежит между ними, и у вас огромное стандартное отклонение.

Если вы хотите знать, что выбросы будут высокими, тогда вы могли бы используйте медиану вместо среднего и ищите значения, которые находятся между минимумом и медианой или равны значению выше медианы:

SELECT dt,
       dept_id,
       sal,
       CASE
       WHEN sal BETWEEN min_sal
                AND     median_sal + ( median_sal - min_sal )
       THEN 'N'
       ELSE 'Y'
       END AS out_of_normal_values
FROM   (
  SELECT t.*,
         MEDIAN( sal ) OVER () AS median_sal,
         MIN(sal) OVER () AS min_sal
  FROM   table_name t
)

Что выводит:

    DT | DEPT_ID |     SAL | OUT_OF_NORMAL_VALUES
-----: | ------: | ------: | :-------------------
201909 |      10 |     230 | N                   
201907 |      10 |     250 | N                   
201909 |      10 |     260 | N                   
201907 |      10 |     290 | N                   
201909 |      10 |     310 | N                   
201907 |      10 |     320 | N                   
201908 |      20 |     700 | N                   
201908 |      20 |     800 | N                   
201908 |      20 |     860 | N                   
201907 |      10 |  100000 | Y                   
201907 |      10 |  500000 | Y                   
201908 |      20 |  850000 | Y                   
201908 |      20 | 1000000 | Y                   

дБ <> скрипка здесь

1 голос
/ 15 апреля 2020

Вы можете использовать join и group by, чтобы получить желаемый результат

select a.date, b.dept_id, a.sal,
    case
        when b.avg_sal < a.sal then 'Y'
        else 'N'
    end as out_of_normal
from tbl a join (
    select dept_id, avg(sal) avg_sal from tbl
    group by dept_id
) b on a.dept_id = b.dept_id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...