Если вы хотите найти значения, которые находятся в пределах двух стандартных отклонений от среднего, тогда вы можете использовать функции 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
дБ <> скрипка здесь