1

Oracle10gR2で次の更新を実行しようとしています。

update
  (select voyage_port_id, voyage_id, arrival_date, port_seq,
    row_number() over (partition by voyage_id order by arrival_date) as new_seq
   from voyage_port) t
set t.port_seq = t.new_seq

Voyage_port_idは主キーであり、voyage_idは外部キーです。各航海の日付に基づいてシーケンス番号を割り当てようとしています。

ただし、上記はORA-01732で失敗します。このビューではデータ操作操作は無効です

問題は何ですか?どうすればそれを回避できますか?

4

4 に答える 4

5

でサブクエリを更新できないため、更新の部分でrow_number行番号を計算する必要があります。set最初に私はこれを試しました:

update voyage_port a
set a.port_seq = (
  select 
    row_number() over (partition by voyage_id order by arrival_date)
  from voyage_port b
  where b.voyage_port_id = a.voyage_port_id
)

しかし、サブクエリは 1 つの行のみを選択し、row_number()常に 1 であるため、これは機能しません。別のサブクエリを使用すると、意味のある結果が得られます。

update voyage_port a
set a.port_seq = (
  select c.rn
  from (
      select 
        voyage_port_id
      , row_number() over (partition by voyage_id 
            order by arrival_date) as rn
      from voyage_port b
   ) c
  where c.voyage_port_id = a.voyage_port_id
)

それは機能しますが、このタスクに期待するよりも複雑です。

于 2009-12-09T13:01:34.017 に答える
2

一部のビューは更新できますが、制限があり、その 1 つは、ビューに分析関数を含めることはできません。UPDATE に関する SQL 言語リファレンスを参照し、「analytic」の最初の出現を検索してください。

これは、航海が同じ日に複数の港を訪問しない場合 (または、日付に時間を一意にする時間要素が含まれている場合) に機能します。

update voyage_port vp
set vp.port_seq =
( select count(*)
  from voyage_port vp2
  where vp2.voyage_id = vp.voyage_id
  and vp2.arrival_date <= vp.arrival_date
)

これは、航海が 1 日に 1 つ以上の港を訪問し、時間コンポーネントがない場合を処理すると思います (ただし、同じ日に訪問した港の順序は任意です)。

update voyage_port vp
set vp.port_seq =
( select count(*)
  from voyage_port vp2
  where vp2.voyage_id = vp.voyage_id
  and (vp2.arrival_date <= vp.arrival_date)
  or (   vp2.arrival_date = vp.arrival_date 
     and vp2.voyage_port_id <= vp.voyage_port_id
     )
)
于 2009-12-09T12:30:48.517 に答える
-1

派生テーブルを更新できるとは思わないでください。次のように書き直します。

update voyage_port
set port_seq = t.new_seq
from
voyage_port p
inner join
  (select voyage_port_id, voyage_id, arrival_date, port_seq,
   row_number() over (partition by voyage_id order by arrival_date) as new_seq
   from voyage_port) t
on p.voyage_port_id = t.voyage_port_id
于 2009-12-09T12:26:44.867 に答える
-2

UPDATE の後の最初のトークンは、更新するテーブルの名前、次に更新する列の名前にする必要があります。selectステートメントで何を達成しようとしているのかはわかりませんが、selectから結果セットを合法的に更新することはできます。
あなたが考えていることを推測すると、SQLのバージョンは次のようになります...

update voyage_port t
set t.port_seq = (<select statement that generates new value of port_seq>)

注: select ステートメントを使用してこのような値を設定するには、 select から 1 行のみが返されるようにする必要があります。

編集:私が説明しようとしていたことを反映するために、上記のステートメントを変更しました。質問は、上記のAndomarによって非常にうまく回答されています

于 2009-12-09T12:30:47.340 に答える