Oracle PL \ SQL для обновления данных с минимальными значениями 2 между двумя датами - PullRequest
1 голос
/ 01 апреля 2020

У меня есть следующая проблема, связанная с показаниями промышленного насоса. Насос обычно имеет счетчик, который ведет учет объема материала, обработанного этим конкретным c насосом. Иногда счетчик необходимо заменить на совершенно новый счетчик (показания счетчика начинаются с 0) или старый рабочий счетчик (показания счетчика могут быть больше 0). У меня есть набор данных, который ведет учет технического обслуживания насоса с показаниями счетчика. И индикация изменения счетчика только тогда, когда у нас есть данные в столбце OLD_METER_READING, в противном случае это пустое. В идеальном случае данные выглядят следующим образом:

PUMP_NO  INSPECTION_DATE MAINTENANCE_TASK  METER_READING  OLD_METER_READING TOTAL_PUMP_LIFE 
11        11-AUG-2000            A             12489                             12489
11        14-JUL-2001            B             14007                             14007
11        03-SEP-2002            Y             0            14007                14007
11        03-SEP-2002            C             0            14007                14007
11        03-SEP-2002            B             0            14007                14007
11        04-JUN-2003            A             1200                              16007 
11        21-DEC-2003            A             8000                              22007
11        23-FEB-2004            Y             0            10000                24007
11        26-MAY-2004            B             10                                24017
11        26-MAY-2004            P             20                                24027
11        26-MAY-2004            R             300                               24307
11        04-OCT-2004            B             2312                              26319
11        31-MAR-2005            A             2889                              26896
11        06-NOv-2006            V             5000                              29007
11        14-JUL-2008            T             0            7000                 31007

Однако во многих случаях специалист по насосам допускает ошибку при регистрации METER_READING во время смены счетчика. Таким образом, данные могут выглядеть примерно так:

PUMP_NO  INSPECTION_DATE MAINTENANCE_TASK METER_READING  OLD_METER_READING TOTAL_PUMP_LIFE 
11        11-AUG-2000             A            12489                            12489
11        14-JUL-2001             B            14007                            14007
11        03-SEP-2002             Y            0            14007                14007
11        03-SEP-2002             C            0            14007                14007
11        03-SEP-2002             B            0            14007                14007
11        04-JUN-2003             A            1200                              16007 
11        21-DEC-2003             A            8000                              22007 
11        23-FEB-2004             Y            0            10000                24007
11        26-MAY-2004             B            10000                             34007
11        26-MAY-2004             P            10000                             34007
11        26-MAY-2004             R            10000                             34007
11        04-OCT-2004             B            2312                              26319
11        31-MAR-2005             A            2889                              26896
11        06-NOV-2006             V            5000                              29007
11        14-JUL-2008             T            0           7000                  31007

Ошибка во втором наборе данных состоит в том, что технический специалист вместо регистрации фактического METER_READING использовал последний METER_READING из старого счетчика в качестве нового METER_READING в день 26-мая-2004. Тем не менее, правильный METER_READING был снова зарегистрирован с 4 октября 2004 года. У нас есть много случаев, когда для определенного c насоса (PUMP_NO) у нас будет ошибочный METER_READING, введенный в базу данных после события изменения счетчика. Это также создает неправильное и запутанное значение для TOTAL_PUMP_LIFE. Итак, чтобы исправить данные, мы хотим добавить еще один столбец в таблицу и обновить таблицу с помощью процедуры Oracle, где процедура будет проверять поле METER_READING со следующими логами c:

  1. проверить данные между двумя последующими событиями смены счетчика. (например, в этом случае между 1-м счетчиком 03-SEP-2002 и 2-й сменой 23-FEB-2004. И снова между 2-й сменой 23-FEB-2004 и 3-й сменой 14-июль-2008).

  2. , если METER_READING между любым из этих периодов выше в предыдущую дату по сравнению с METER_READING в предыдущую дату, тогда обновите более высокое METER_READING со вторым самым низким значением (0 и 2312 являются самыми низкими 2, поэтому обновление с 2312) в этом периоде.

Таким образом, период между первыми 2 изменениями счетчика пройдет, и обновление не потребуется. Однако во втором наборе даты все значения (10000) в столбце METER_READING для 26 мая 2014 года будет обновлено значение 2312.

Я не уверен, как написать PL \ SQL для сравнения значений между двумя событиями. а также как обновить значение предыдущей даты (если в столбце METER_READING обнаружено более высокое значение), указав меньшее значение между этим периодом.

База данных: Oracle SQL 11g

Ответы [ 2 ]

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

Итак, глядя на вашу проблему, я не знаю, что вам нужно прибегнуть к PL / SQL. Следующий запрос должен помочь вам определить, какие записи необходимо обновить:

SELECT m.*, 
       MIN(meter_reading) 
         OVER (PARTITION BY m.pump_no 
               ORDER BY m.inspection_date
               RANGE BETWEEN NVL((SELECT min(n.inspection_date)-m.inspection_date
                                  FROM maintenance n
                                  WHERE n.inspection_date > m.inspection_date),
                                  0) FOLLOWING 
                      AND NVL((SELECT min(n.inspection_date)-m.inspection_date-1
                               FROM maintenance n
                               WHERE n.old_meter_reading IS NOT NULL
                               AND n.inspection_date > m.inspection_date),
                              0) FOLLOWING) AS MIN_READING_FOLLOWING
FROM maintenance m
ORDER BY m.inspection_date, old_meter_reading ASC NULLS LAST;

Я создал SQLFiddle для демонстрации запроса. ( Link )

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

Вы можете использовать это как часть оператора обновления. Что касается TOTAL_PUMP_LIFE, может быть проще всего пересчитать это после того, как вы исправили meter_readings как часть отдельной операции.

Правка 1: добавление PL / SQL для обновления

DECLARE
  CURSOR c_readings IS
    SELECT m.*, 
           MIN(meter_reading) 
             OVER (PARTITION BY m.pump_no 
                   ORDER BY m.inspection_date
                   RANGE BETWEEN NVL((SELECT min(n.inspection_date)-m.inspection_date
                                      FROM maintenance n
                                      WHERE n.inspection_date > m.inspection_date), 
                                      0) FOLLOWING 
                          AND NVL((SELECT min(n.inspection_date)-m.inspection_date-1
                                   FROM maintenance n
                                   WHERE n.old_meter_reading IS NOT NULL
                                   AND n.inspection_date > m.inspection_date),
                                  0) FOLLOWING) AS MIN_READING_FOLLOWING
    FROM maintenance m
    ORDER BY m.inspection_date, old_meter_reading ASC NULLS LAST;
BEGIN
  FOR rec IN c_readings LOOP
    IF rec.meter_reading > rec.min_reading_following THEN
      UPDATE maintenance m
      SET m.meter_reading = rec.min_reading_following
      WHERE m.pump_no = rec.pump_no
      AND m.inspection_date = rec.inspection_date
      AND m.maintenance_task = rec.maintenance_task;
    END IF;
  END LOOP;
END;
/

Вам нужно будет либо COMMIT, когда это будет сделано, либо добавить его в код.

0 голосов
/ 11 апреля 2020

Возможно, вам нужно сделать что-то вроде этого:

update MyTable mt1
set value = (select min(value)  
           from MyTable2 mt2
         where mt1.id = mt2.id  --your relation
           and value NOT IN (select min(value)  
                               from MyTable2 mt3
                               where mt2.id = mt3.id))

С этим обновлением вы получаете минимальное значение, а не минимальное оригинальное значение с NOT IN.

...