J'obtiens "ORA-01779: impossible de modifier une colonne qui mappe vers une table non conservée par clé" lorsque j'essaie de mettre à jour une jointure. J'ai parcouru le site et trouvé beaucoup de conseils sur ce que signifie la clé préservée et pourquoi elle est nécessaire ... mais d'aussi près que je puisse dire, je suis conforme à ces conseils et j'obtiens toujours l'erreur.
J'ai deux tables:
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)
La mise à jour que j'exécute est:
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';
Je ne mets à jour que les valeurs d'une table (PG_MACHINE) et la colonne de jointure de l'autre table est la clé primaire, ce qui devrait la rendre préservée par ma lecture. Je crains que la clause where ne cause le problème, mais j'ai essayé de supprimer le filtre sur mac.update_time et j'ai eu la même erreur, et loc.dnsname a une contrainte unique.
Ce qui est encore plus étrange, c'est que nous avons, comme beaucoup de gens, un environnement de développement et de production. Nous avons fait un schéma complet et une migration des données de prod à dev. Je les ai regardés tous les deux et ils ont des index et des contraintes identiques. La requête fonctionne en dev, mais génère l'erreur ci-dessus dans prod.
Donc deux questions:
1) Pouvez-vous voir ce qui ne va pas avec ma requête? 2) Pouvez-vous suggérer ce qui pourrait être différent entre mon environnement de développement et de production (par exemple, les paramètres du serveur) qui pourrait provoquer cette erreur dans l'un mais pas dans l'autre?
Vous pouvez mettre à jour une jointure dans Oracle si les les conditions suivantes sont remplies :
(supplémentaires restrictions sur la mise à jour des vues s'appliquent)
Dans votre exemple, vous mettez à jour la table PG_MACHINE
seulement. Oracle doit s'assurer que pour une seule ligne de ce tableau, une seule ligne de l'autre peut être trouvée. Cela semble être le cas puisque vous avez un PK sur PG_LABLOCATION.LABLOCID
. Par conséquent, vous devriez pouvoir mettre à jour la jointure. Voir par exemple ceci SQLFiddle avec une configuration similaire .
Dans votre cas, vous devez soit:
MERGE
si PG_LABLOCATION.LABLOCID
est unique pour la requête pertinente. MERGE
est moins strict que la mise à jour avec des jointures et ne retournera une erreur que s'il y a en fait un doublon dans le jeu de résultats (alors que UPDATE
échouera s'il y a est la possibilité d'un doublon).examinez votre requête, puisque vous n'avez pas besoin des valeurs de la table parent dans la clause SELECT
, vous pouvez la réécrire en semi-jointure (ce qui garantit qu'aucun doublon ne sera généré):
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');
Cela pourrait être réécrit comme suit:
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;
Dans ce cas, j'irais avec la troisième option: en général , vous ne pouvez pas mettre à jour le parent dans une jointure parent-enfant .