Oracle
 sql >> Base de données >  >> RDS >> Oracle

SGBD Oracle - Lire une table avant de traiter Mise à jour dans un déclencheur AFTER - table de mutation

Juste pour clarifier, l'exception de table de mutation est levée parce que vous essayez de lire à partir des rooms table dans votre fonction, pas parce que vous essayez de lire à partir des properties table. Puisque vous avez un déclencheur au niveau de la ligne sur rooms , cela signifie que les rooms table est au milieu d'une modification lorsque le déclencheur au niveau de la ligne se déclenche et qu'il peut être dans un état incohérent. Oracle vous empêche d'interroger les rooms tableau dans cette situation car les résultats ne sont pas nécessairement déterministes ou reproductibles.

Si vous avez créé un déclencheur au niveau de l'instruction (en supprimant le FOR EACH ROW ) et y mettre votre logique, vous ne rencontrerez plus d'exception de table en mutation car les rooms table ne serait plus dans un état incohérent. Un déclencheur au niveau de l'instruction, cependant, n'est pas en mesure de voir quelles lignes ont été modifiées. Cela signifierait que vous auriez besoin d'examiner toutes les propriétés pour voir quelles valeurs de statut doivent être ajustées. Cela ne sera pas particulièrement efficace.

Au prix d'une complexité supplémentaire, vous pouvez améliorer les performances en capturant les propriétés modifiées dans un déclencheur au niveau de la ligne, puis en vous y référant dans un déclencheur au niveau de l'instruction. Cela nécessite généralement trois déclencheurs et un package, ce qui augmente évidemment considérablement le nombre de pièces mobiles (si vous êtes sur 11.2, vous pouvez utiliser un déclencheur composé avec trois déclencheurs de composants, ce qui simplifie un peu les choses en éliminant le besoin d'utiliser le package) . Cela ressemblerait à quelque chose comme

CREATE OR REPLACE PACKAGE trigger_collections
AS
  TYPE modified_property_tbl IS TABLE OF properties.property_id%type;
  g_modified_properties modified_property_tbl;
END;

-- Initialize the collection in a before statement trigger just in case
-- there were values there from a prior run
CREATE OR REPLACE TRIGGER trg_initialize_mod_prop_coll
  BEFORE INSERT OR UPDATE ON rooms
BEGIN
  trigger_collections.g_modified_properties := trigger_collections.modified_property_tbl();
END;

-- Put the property_id of the modified row in the collection
CREATE OR REPLACE TRIGGER trg_populate_mod_prop_coll
  AFTER INSERT OR UPDATE ON rooms
  FOR EACH ROW
BEGIN
  trigger_collections.g_modified_properties.extend();
  trigger_collections.g_modified_properties( trigger_collections.g_modified_properties.count + 1 ) := :new.property_id;
END;

CREATE OR REPLACE TRIGGER trg_process_mod_prop_coll
  AFTER INSERT OR UPDATE ON rooms
BEGIN
  FOR p IN 1 .. trigger_collections.g_modified_properties.count
  LOOP
    IF prop_vacancy_query( trigger_collections.g_modified_properties(i) ) = 0 
    THEN
      ...
END;