Как изолировать строку, которая содержит значение в отличие от других значений в этом столбце в запросе SQL Server? - PullRequest
1 голос
/ 17 октября 2019

Я пытаюсь написать запрос в SSMS 2016, который изолирует значения для группы, которые отличаются от других значений в столбце. Я могу объяснить лучше на примере:

Каждый элемент оборудования в нашем автопарке имеет показания счетчика часов, которые записываются с портативного устройства. Иногда люди в поле вводят в счетчик опечаток, которые искажают наши почасовые показания.

Таким образом, история счетчиков юнитов может выглядеть так:

10/1/2019: 2000    
10/2/2019: 2208    
10/4/2019: 2208    
10/7/2019: 2212    
10/8/2019: 2    
10/8/2019: 2225   
...etc.

Очевидно, что «2» - плохая запись, потому что счетчик часов никогда не может уменьшиться. редактировать: иногда может встречаться противоположный край, когда они вводят чтение, например «22155», и тогда мне нужен запрос для адаптации, чтобы найти значения, которые слишком высоки, и также изолировать их. Эти данные хранятся в таблице истории счетчиков, где для каждого показания счетчика имеется одна строка. Мне поручено создать процедуру, которая автоматически изолирует неверные данные и удалит эти строки из таблицы. Как я могу написать запрос, который понимает контекст истории счетчика и знает, что 2 - это плохо?

Любые советы приветствуются, заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 17 октября 2019

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

DECLARE @Median numeric(22,0);
;with CTE as
(
select t.*, row_number() over (order by t.value) as "rn" from t
)
select @Median = cte.value
where cte.rn = (select (SUM( MAX(RN) + MIN(RN)) / 2 from cte); -- floors if dividing an odd number
select * from dataReadings where reading_value < (0.8 * @median) OR reading_value > (1.2 * @median);

Цель этого - дать вам диапазон среднего значения +/- 20%, который не должен быть искажен ошибками, как в среднем. Опять же, это предполагает, что ваши значения должны попадать в приемлемый диапазон.

Если это должно быть постоянно увеличивающееся чтение, и вы не должны когда-либо сталкиваться с более низкими значениями, ответ Гордона идеален.

0 голосов
/ 18 октября 2019

Я бы подумал, чтобы посмотреть на изменение каждого чтения от среднего значения чтения. (Я взял чек lag() из ответа @Gordon Linoff.) Например:

create table #test (the_date date, reading int)
insert #test (the_date, reading) values ('10/1/2019', 2000)
                                      , ('10/2/2019', 2208)
                                      , ('10/4/2019', 2208)
                                      , ('10/7/2019', 2212)
                                      , ('10/8/2019', 2)
                                      , ('10/8/2019', 2225)
                                      , ('10/8/2019', 2224)
                                      , ('10/9/2019', 22155)

declare @avg int, @stdev float
select @avg = avg(reading)
     , @stdev = stdev(reading) * 0.5
  from #test

select t.*
     , case when reading < @avg - @stdev then 'SUSPICIOUS - too low'
            when reading > @avg + @stdev then 'SUSPICIOUS - too high'
            when reading < prev_reading then 'SUSPICIOUS - decrease'
       end Comment
from (select t.*, lag(reading) over (order by the_date) as prev_reading
      from #test t
     ) t

Что приводит к:

the_date    reading prev_reading    Comment
2019-10-01  2000    NULL    NULL    
2019-10-02  2208    2000    NULL    
2019-10-04  2208    2208    NULL    
2019-10-07  2212    2208    NULL    
2019-10-08  2   2212    SUSPICIOUS - too low    
2019-10-08  2225    2   NULL    
2019-10-08  2224    2225    SUSPICIOUS - decrease   
2019-10-09  22155   2224    SUSPICIOUS - too high   
0 голосов
/ 17 октября 2019

Вы можете использовать фильтр, чтобы избавиться от «уменьшения»:

select t.*
from (select t.*, lag(col2) over (order by col1) as prev_col2
      from t
     ) t
where prev_col2 < col2;

Я бы не советовал «автоматически удалять» такие записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...