Как мне поменять местами значения записей в Oracle SQL?

#sql #oracle

#sql #Oracle

Вопрос:

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

1439 ATL SFO
1440 SFO ATL

в конечном итоге будет выглядеть:

1440 ATL SFO
1439 SFO ATL

Я попробовал этот запрос (потому что вы не можете ОБНОВИТЬ .. ПРИСОЕДИНИТЬСЯ в Oracle):

 UPDATE
   (SELECT f.airline, f.flightno flightno_f, d.airline, d.flightno flightno_d
       FROM flights f
       INNER JOIN flights d ON f.airline = 9 AND
         f.sourceairport = d.destairport AND
         f.destairport = d.sourceairport AND d.airline = 9
       WHERE d.flightno < f.flightno) g
   SET g.flightno_f = g.flightno_d,
     g.flightno_d = g.flightno_f;
  

где airline, flightno является первичным ключом для таблицы рейсов. Выбор дает мне правильный набор записей, на которые я хочу поменять местами, но ОБНОВЛЕНИЕ… SET выдает мне эту ошибку:

    SET g.flightno_f = g.flightno_d,
       *
ERROR at line 7:
ORA-01779: cannot modify a column which maps to a non key-preserved table
  

Есть идеи о том, где я ошибаюсь?

Комментарии:

1. @therin Попробуйте добавить ограничение изменить таблицу рейсов, добавить ограничение flights_uk unique (flightno);

2. Добавить ограничение к созданному мной представлению g? Я не уверен, что вы имеете в виду. Я попытался добавить другое ограничение в таблицу рейсов, но одна из других основных проблем, с которыми я столкнулся, заключается в том, что я не могу добавить уникальное ограничение только для номера рейса, может быть идентичный номер рейса для другой авиакомпании.

3. @therin Это проблема, с которой вы сталкиваетесь, поскольку у вас идентичный номер рейса, который он не может обновить

4. @Sam: это один из обязательных шагов. Но другой шаг — написать запрос (вложенный select), который возвращает однозначный результирующий набор.

5. Это то, о чем я думал изначально, но когда я на самом деле выполняю запрос, повторяющихся номеров рейсов нет , потому что я отфильтровываю их все. Есть ли какой-либо ручной способ обойти это?

Ответ №1:

Для обновления соединения не имеет значения, что выбранный вами набор данных фактически сохранен с ключом; Oracle должен иметь возможность видеть из ограничений и предикатов, что он по определению будет сохранен с ключом. И поскольку у вас есть условие неравенства для flightnumber, в определении данных нет ничего, что гарантировало бы, что у вас не будет нескольких совпадений для данной исходной строки.

Если гарантировано, что номера рейсов всегда будут отличаться на 1, вы могли бы использовать метод join, если измените условие на d.flightno 1 = f.flightno .

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

 UPDATE flights f1
  SET flightno =
    (SELECT flightno
       FROM flights f2
       WHERE f2.airline = f1.airline
         AND f2.sourceairport = f1.destairport
         AND f2.destairport = f1.sourceairport
    )
  WHERE airline = 9;