0
votes

Déclencheur SQL pour arrêter la mise à jour lorsqu'une condition est remplie

J'ai 3 tableaux: Projets , Composants et Fournisseurs .

Ce que j'essaie de faire, c'est d'écrire un déclencheur qui ne permet pas de modifier la valeur de city si le composant et le projet ont la même ville que le fournisseur.

Ce que j'ai essayé jusqu'à présent:

Error at line 3: PL/SQL: SQL Statement ignored

Après avoir essayé d'exécuter ceci, j'obtiens l'erreur suivante:

Error at line 3: PLS-00103: Encountered the symbol "JOIN" when expecting one of the following:

   ) , with group having intersect minus order start union where
   connect

Veuillez noter que le numéro de ligne fait référence au nombre de la ligne après BEGIN!

J'ai également essayé d'écrire la partie declare avant BEGIN, j'obtiens l'erreur suivante:

create or replace TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
BEGIN
    DECLARE v_counter NUMBER := 0;
    SELECT COUNT(*) FROM (SELECT * FROM Suppliers s JOIN Projects p ON (s.city=p.city) JOIN Components c ON (c.city=s.city)) INTO v_counter;
    IF (v_counter != 0)
    THEN
        raise_application_error(-20111,'Can't change the city for this supplier!');
    END IF;
END;

Ce qui doit être fait afin de se débarrasser de ces erreurs?


1 commentaires

Dans votre cas, plutôt que de créer un déclencheur qui ne permet pas la mise à jour, vous devez avoir créé un déclencheur qui aurait mis à jour l'autre table de remorquage, cela aurait été une conception robuste.


4 Réponses :


0
votes

Vous essayez d'accéder à la variable qui est assignée à zéro dans la déclaration. définir la variable à partir de la requête (le résultat sera un nombre)

create or replace TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
BEGIN
    DECLARE v_counter NUMBER := 0;
-- change this line
    SET v_counter = (SELECT COUNT(*) FROM (SELECT * FROM Suppliers s JOIN Projects p ON (s.city=p.city) JOIN Components c ON (c.city=s.city)));
    IF (v_counter != 0)
    THEN
        raise_application_error(-20111,'Can't change the city for this supplier!');
    END IF;
END;

a changé la requête de comptage en une requête modifiée. Exécutez d'abord simplement la requête SELECT COUNT (*) FROM (SELECT * FROM Fournisseurs s JOIN Projects p ON (s.city = p.city) JOIN Components c ON (c.city = s.city)) code > si la sortie est un nombre alors affectez à la variable v_counter


2 commentaires

Merci pour votre réponse! J'ai essayé cela mais j'obtiens toujours cette erreur qui indique qu'il a rencontré JOIN alors qu'il attendait autre chose


Exécutez d'abord simplement la requête SELECT COUNT (*) FROM (SELECT * FROM Fournisseurs s JOIN Projects p ON (s.city = p.city) JOIN Components c ON (c.city = s.city)) si la sortie est un nombre alors affectez à la variable v_counter



2
votes

Il y a des erreurs de syntaxe.

  1. DECLARE précède l'instruction BEGIN .
  2. INTO va après SELECT et avant FROM .
  3. À rise_application_error (-20111, 'Impossible de changer la ville pour ce fournisseur!'); vous ne pouvez pas écrire Can't car le premier guillemet simple se terminera à la citation de Can't provoquant la fin de la chaîne. Vous devez donc le supprimer ou faire: rise_application_error (-20111, 'Impossible de changer la ville pour ce fournisseur!');

Cela dit, le code complet devrait ressembler à:

CREATE OR REPLACE TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
DECLARE
    v_counter NUMBER := 0;
BEGIN
    SELECT COUNT(*) 
    INTO v_counter
    FROM (SELECT * FROM Suppliers s JOIN Projects p ON s.city=p.city JOIN Components c ON c.city=s.city);

    IF v_counter != 0 THEN
        raise_application_error(-20111,'Can''t change the city for this supplier!');
    END IF;

END;

J'espère que cela vous aidera.


0 commentaires

0
votes

Vérifiez, par lower () ou upper () pour faire correspondre, y compris insensibilité à la casse, si une ville correspond à l'ensemble des valeurs du projet du tableau.

Vous ne le faites pas. Il n'est pas nécessaire et ne doit pas utiliser la table Supplier dans l'instruction select en raison du risque que le nom de la table soit une erreur de mutation:

CREATE OR REPLACE TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
DECLARE 
    v_counter PLS_INTEGER;
BEGIN
    SELECT COUNT(*) 
      INTO v_counter
      FROM Projects p 
     WHERE lower(:new.city)=lower(p.city);

    IF (v_counter != 0) THEN
        raise_application_error(-20111,'Can''t change the city for this supplier!');
    END IF;
END;

où une initialisation est redondante pour v_counter , s'il n'y a pas d'enregistrement correspondant trouvé, il serait déjà nul. De plus, notez l'ordre du mot-clé declare , y compris une partie de définition de variable.


0 commentaires

0
votes

Il n'y a pas besoin de frais généraux d'une jointure ni même de transfert d'aucune date. En supposant que City soit indexé dans les projets et les composants (devrait probablement être un FK indexé), ce qui suit ne nécessite qu'un simple test d'index sur chaque table.

create or replace trigger supplier_control
before update of city
on suppliers
for each row
declare 
    project_component_exists integer ;
begin
    select null
      into project_component_exists
      from dual
     where exists ( select null 
                      from projects  
                     where city = :old.city
                  ) 
       and exists ( select null 
                      from components  
                     where city = :old.city
                  );
    raise_application_error(-20111,'Can''t change the city for this supplier!');                  
exception 
 when no_data_found
 then null;    
end;   


0 commentaires