Встроенное представление Oracle вызывает проблемы с выражением обновления - PullRequest
0 голосов
/ 28 марта 2019

Я получаю сообщение об ошибке «ORA-01779: невозможно изменить столбец, который сопоставляется с таблицей без сохранения ключа» с этим запросом:

UPDATE 
 (SELECT P.SERVICE_DATE_OUT AS P_DATEOUT, P.SERVICE_DATE_IN AS P_DATEIN
  FROM TRANSLOG TL JOIN PMEQMT P ON TL.ITEMNO = P.EQNO
  WHERE TL.LOC_DESC = 'E-IN SERVICE')
SET P_DATEOUT = NULL, P_DATEIN = NULL

После исследования я считаю, что эта ошибка связана с созданием встроенного представления и обновлением, которое пытается обновить обе таблицы, а не ту, которую я хочу? Кто-нибудь может это подтвердить? Есть ли работа вокруг?

Для более подробного объяснения моего сценария я построил два других запроса, которые будут выполняться ежедневно перед запуском вышеописанного (если я смогу заставить что-то работать).

Первый:

  UPDATE PMEQMT P
   SET SERVICE_DATE_OUT = (SELECT MAX(TL.TRANS_DATE)
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND 
                              TL.LOC_DESC = 'E-OUT OF SERVICE' AND
                              TL.TRANS_DATE >= SYSDATE - 1 AND
                              TL.TRANS_IN_OUT = 'IN'
                       )
WHERE P.CLASS = 'TL' AND
      P.SERVICE_DATE_OUT IS NULL

Второе:

UPDATE PMEQMT P
   SET SERVICE_DATE_IN =
   CASE 
   WHEN SERVICE_DATE_IN IS NULL THEN (SELECT MAX(TL.TRANS_DATE)
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND 
                              TL.LOC_DESC = 'E-IN SERVICE' AND
                              TL.TRANS_DATE >= SYSDATE - 1 AND
                              TL.TRANS_IN_OUT = 'IN'
                       )
   WHEN (TRUNC(SERVICE_DATE_IN)) <= (TRUNC(SYSDATE)) THEN (SELECT ((TRUNC(SYSDATE))+1)
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND
                        TL.LOC_DESC = 'E-OUT OF SERVICE'
                       )
   WHEN (TRUNC(SERVICE_DATE_IN)) > (TRUNC(SYSDATE)) THEN (SELECT SERVICE_DATE_IN 
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND
                        TL.LOC_DESC = 'E-OUT OF SERVICE'
                       )
   END
WHERE CLASS = 'TL'

Есть ли способ объединить их? Все три, если функционирует самый первый запрос, если нет, то два последних? Имеет ли смысл объединять их или мне лучше оставить их отдельно?

Любой вклад приветствуется.

1 Ответ

2 голосов
/ 29 марта 2019

Что касается вашего первого запроса. Чтобы обновить представление объединения (вложенный элемент выбора превращается в представление внутри), должны быть выполнены следующие условия:

  • Любая операция INSERT, UPDATE или DELETE в представлении объединения может изменять одновременно только одну базовую базовую таблицу. (Это нормально для вашего запроса, вы обновляете только PMEQMT таблицу.)
  • Все обновляемые столбцы представления объединения должны отображаться в столбцы таблицы с ключами . (И вот тут у тебя неприятности).

Второе условие означает, что каждая строка таблицы должна иметь только одну соответствующую строку в объединенной таблице (отношение один к одному).

Подробнее об этом можно прочитать здесь .

Чтобы обойти эту ошибку, вы можете переписать оператор обновления в оператор слияния:

merge into PMEQMT t
using (SELECT P.EQNO
          FROM TRANSLOG TL JOIN PMEQMT P ON TL.ITEMNO = P.EQNO
       WHERE TL.LOC_DESC = 'E-IN SERVICE') u
on (u.EQNO = t.EQNO)
when matched then update set t.P_DATEOUT = NULL, t.P_DATEIN = NULL;

Что касается двух последних запросов, вы можете объединить их в один запрос:

UPDATE PMEQMT P
   SET SERVICE_DATE_OUT = case when P.SERVICE_DATE_OUT IS NULL then(SELECT MAX(TL.TRANS_DATE)
                                                                    FROM TRANSLOG TL
                                                                    WHERE P.EQNO = TL.ITEMNO AND 
                                                                          TL.LOC_DESC = 'E-OUT OF SERVICE' AND
                                                                          TL.TRANS_DATE >= SYSDATE - 1 AND
                                                                          TL.TRANS_IN_OUT = 'IN'
                                                                   ) 
                          else P.SERVICE_DATE_OUT end,
       SERVICE_DATE_IN =
               CASE 
               WHEN SERVICE_DATE_IN IS NULL THEN (SELECT MAX(TL.TRANS_DATE)
                                    FROM TRANSLOG TL
                                    WHERE P.EQNO = TL.ITEMNO AND 
                                          TL.LOC_DESC = 'E-IN SERVICE' AND
                                          TL.TRANS_DATE >= SYSDATE - 1 AND
                                          TL.TRANS_IN_OUT = 'IN'
                                   )
               WHEN (TRUNC(SERVICE_DATE_IN)) <= (TRUNC(SYSDATE)) THEN (SELECT ((TRUNC(SYSDATE))+1)
                                    FROM TRANSLOG TL
                                    WHERE P.EQNO = TL.ITEMNO AND
                                    TL.LOC_DESC = 'E-OUT OF SERVICE'
                                   )
               WHEN (TRUNC(SERVICE_DATE_IN)) > (TRUNC(SYSDATE)) THEN (SELECT SERVICE_DATE_IN 
                                    FROM TRANSLOG TL
                                    WHERE P.EQNO = TL.ITEMNO AND
                                    TL.LOC_DESC = 'E-OUT OF SERVICE'
                                   )
               END     
WHERE P.CLASS = 'TL'; 

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

...