結合を更新しようとすると、「ORA-01779:キーが保存されていないテーブルにマップする列を変更できません」というメッセージが表示されます。サイトを検索したところ、キー保持の意味とそれが必要な理由について多くのアドバイスが見つかりました...しかし、私が知る限り、そのアドバイスを順守しているにもかかわらず、エラーが発生します。
2つのテーブルがあります。
PG_LABLOCATION has, among other things, the columns:
"LABLOCID" NUMBER,
"DNSNAME" VARCHAR2(200 BYTE)
LABLOCID is the primary key, DNSNAME has a unique constraint
PG_MACHINE has, among other things, the columns:
"MACHINEID" NUMBER,
"LABLOCID" NUMBER,
"IN_USE" NUMBER(1,0) DEFAULT 0,
"UPDATE_TIME" TIMESTAMP (6) DEFAULT '01-JAN-1970'
MACHINEID is a primary key
LABLOCID is a foreign key into LABLOCID in PG_LABLOCATION (its primary key)
私が実行している更新は:
update
(select mac.in_use, mac.update_time
from pg_machine mac
inner join pg_lablocation loc
on mac.lablocid = loc.lablocid
where loc.dnsname = 'value'
and '02-JAN-2013' > mac.update_time
)
set in_use = 1 - MOD( 101, 2 ), update_time = '02-JAN-2013';
私は1つのテーブル(PG_MACHINE)の値のみを更新しており、もう1つのテーブルの結合列は主キーです。これにより、読み取りによってキーが保持されます。 where句が問題を引き起こしているのではないかと心配していますが、mac.update_timeでフィルターを削除しようとすると同じエラーが発生し、loc.dnsnameには一意の制約があります。
さらに奇妙なのは、多くの人々のように、開発環境と製品環境があるということです。 prodからdevへの完全なスキーマとデータの移行を行いました。私はそれらの両方を調べましたが、それらには同じインデックスと制約があります。クエリはdevで機能しますが、prodで上記のエラーを生成します。
したがって、2つの質問:
1)私のクエリのどこが悪いのか分かりますか? 2)私の開発環境と本番環境の違い(サーバー設定など)によって、一方ではこのエラーが発生するが、他方では発生しない可能性があることを示唆できますか?
次の条件を満たす場合 の場合、Oracleの結合を更新できます。
(追加 ビューの更新に関する制限 が適用されます)
あなたの例では、テーブルPG_MACHINE
のみを更新します。 Oracleは、このテーブルの1つの行に対して、もう1つの行しか見つからないことを確認する必要があります。 PG_LABLOCATION.LABLOCID
にPKがあるため、これが当てはまるようです。したがって、結合を更新できるはずです。たとえば、この SQLFiddleと同様の設定 を参照してください。
あなたの場合、あなたはどちらかをするべきです:
MERGE
PG_LABLOCATION.LABLOCID
が関連するクエリに対して一意である場合。 MERGE
は結合による更新よりも厳密ではなく、結果セットに実際に重複がある場合にのみエラーを返します(UPDATE
は重複の可能性がある場合は失敗します)。クエリを確認します。SELECT
句の親テーブルの値は必要ないため、準結合として書き換えることができます(これにより、重複が生成されないことが保証されます)。
UPDATE (SELECT mac.in_use, mac.update_time
FROM pg_machine mac
WHERE mac.lablocid IN (SELECT loc.lablocid
FROM pg_lablocation loc
WHERE loc.dnsname = 'value')
AND to_date('02-JAN-2013') > mac.update_time)
SET in_use = 1 - MOD(101, 2),
update_time = to_date('02-JAN-2013');
これは次のように書き直すことができます。
UPDATE pg_machine mac
SET in_use = 1 - MOD(101, 2),
update_time = to_date('02-JAN-2013')
WHERE mac.lablocid IN (SELECT loc.lablocid
FROM pg_lablocation loc
WHERE loc.dnsname = 'value')
AND to_date('02-JAN-2013') > mac.update_time;
この場合、3番目のオプションを使用します。通常親子結合で親を更新することはできません。