Newsgroup: it.comp.software.database
Titolo: aiuto trigger oracle

Salve, mi servirebbe aiuto con i trigger in oracle 10g per un progetto
scolastico.
In tutto sono 4, ma per ora indico i primi 2.
Il primo trigger coinvolge una tabella Banchetti e una Menu. La
relazione è 1:N.
In Banchetti, tra le altre cose, ho il codice di Menu come chiave
esterna, il costo totale e il numero di invitati. In Menu ho Codice e
Costo.
Il trigger deve mostrare un messaggio di warning se il costo totale del
banchetto in fase di inserimento non corrisponde al prodotto
CostoMenu*Invitati.
Questo è il codice che ho scritto:
CREATE OR REPLACE TRIGGER COSTOBANCHETTO
BEFORE INSERT ON Banchetti
FOR EACH ROW
DECLARE
  costoMenu NUMBER;
  costoBanchetto NUMBER;
BEGIN
  SELECT Menu.Costo INTO costoMenu
  FROM Menu, Banchetti
  WHERE (:new.MEN_CODICE) = Menu.CODICE;
  costoBanchetto := costoMenu * (:new.NumeroInvitati);
  IF ((:new.CostoTotale) != costoBanchetto) THEN
    Dbms_output.put_line ('ATTENZIONE!! Il costo totale non
corrisponde al prodotto CostoMenu * N.Invitati');
  END IF;
END;
Ho inserito un nuovo banchetto con Menù n.1 (di costo 100) e Invitati
= 3. Ho specificato un costo totale di 100, dunque non corrispondente
al prodotto CostoMenu*Invitati:
ERRORE alla riga 1:
ORA-01422: Estrazione esatta riporta numero di righe maggiore di quello
richiesto
ORA-06512: a "COSTOBANCHETTO", line 5
ORA-04088: errore durante esecuzione del trigger
'COSTOBANCHETTO'
_______________________________________________________________________
Secondo trigger: le tabelle coinvolte sono sempre le stesse. Nel caso
di modifica del costo di un menù si devono aggiornare tutti i
CostoTotale dei Banchetti che si riferivano a quel menù, solo se il
vecchio costo menù era pari al prodotto Costo*Invitati.
Codice:
CREATE OR REPLACE TRIGGER T_COSTOMENU
BEFORE UPDATE OF Costo ON Menu
FOR EACH ROW
DECLARE
  CURSOR c IS
   SELECT  CostoTotale, NumeroInvitati
   FROM Banchetti
   WHERE MEN_CODICE = (:new.CODICE);
   vecchioCostoBanchetto NUMBER:=0;
  nuovoCostoBanchetto NUMBER:=0;
BEGIN
  FOR record IN c LOOP
    vecchioCostoBanchetto := (record.NumeroInvitati * (:old.Costo));
    nuovoCostoBanchetto := (record.NumeroInvitati * (:new.Costo));
    IF (record.CostoTotale = oldCostoBanchetto) THEN
       UPDATE Banchetti
       SET CostoTotale := nuovoCostoBanchetto
       WHERE Banchetti.MEN_CODICE = (:old.CODICE);
    END IF;
  END LOOP;
END;
Errori di compilazione:
LINE/COL ERROR
-------- --------------------------------------------------
13/8     PL/SQL: SQL Statement ignored
14/24    PL/SQL: ORA-00927: segno '=' mancante
Qualcuno può darmi una mano?

Lisa Simpson ha scritto:

Penso siano solo due sviste:
1)
Probabilmente intendevi scrivere
SELECT Menu.Costo INTO costoMenu
FROM Menu
e non
SELECT Menu.Costo INTO costoMenu
FROM Menu, Banchetti
In questo modo, non essendoci condizioni di join, selezioni un numero
di record pari al numero di record della tabella Banchetti e non un
solo record come richiede l'utilizzo di "INTO"!
2)
La query:
UPDATE Banchetti
       SET CostoTotale := nuovoCostoBanchetto
       WHERE Banchetti.MEN_CODICE = (:old.CODICE)
è errata. Il simbolo ":=" serve per assegnare valori alle variabili in
PL/SQL: nelle query si usa "=".
Ciao


Infatti era così. Eppure li avevo riletti tante volte.
Ti ringrazio tantissimo.
Ora funzionano... soltanto che non appare alcun warning (con
riferimento al primo trigger) se l'inserimento è fatto dalle maschere.
Inserendo i dati da sqlplus console con l'impostazione "set
serveroutput on" il warning appare correttamente quando c'è
violazione.
E' normale?
Purtroppo ho problemi anche con gli altri 2 trigger che avevo
menzionato nel primo post. Se potessi darmi una mano anche con questi
mi faresti un enorme favore.
________________________________________________________________
Trigger 3: tenere aggiornato il n. invitati e costo banchetti nel caso
di insert e delete sulla tabella invitati.
Tabelle: Banchetti (Codice, NumeroInvitati, CostoTotale....) con chiave
Codice
Invitati (Cognome, Nome, Ban_Codice) con chiave tutti i campi
Il codice è questo:
CREATE OR REPLACE TRIGGER T_INVITATI
BEFORE INSERT OR DELETE ON INVITATI
FOR EACH ROW
DECLARE
  costoMenu NUMBER;
BEGIN
  SELECT Costo INTO costoMenu
  FROM Menu, Banchetti
  WHERE (:new.Ban_Codice = Banchetti.Codice) AND (Banchetti.Men_Codice
= Menu.Codice);
  IF INSERTING THEN
    UPDATE Banchetti
    SET NumeroInvitati = NumeroInvitati + 1, CostoTotale =
(NumeroInvitati+1) * costoMenu
    WHERE (:new.BAN_CODICE) = Banchetti.Codice;
ELSE
    UPDATE Banchetti
    SET NumeroInvitati = NumeroInvitati - 1, CostoTotale =
(NumeroInvitati-1) * costoMenu
    WHERE (:new.BAN_CODICE) = Banchetti.Codice;
  END IF;
END;
In caso di inserimenti in Invitati non ho alcun problema. N. invitati e
costo vengono aggiornati correttamente.
In caso di delete appare questo errore:
SQL> delete from invitati where nome = 'Lisa';
delete from invitati where nome = 'Lisa'
            *
ERRORE alla riga 1:
ORA-01403: nessun dato trovato
ORA-06512: a "T_INVITATI", line 4
ORA-04088: errore durante esecuzione del trigger 'T_INVITATI'
____________________________________________________
Trigger 4: verificare che il n. posti disponibili per un ristorante non
sia inferiore alla somma del n. di invitati per i banchetti organizzati
da quel ristorante nella stessa data
Tabelle:
Ristoranti (Nome, Citta, Indirizzo, NumeroPosti...) con chiave
Nome,Citta,Indirizzo
Banchetti (Codice, Data, NumeroInvitati, CostoTotale, Occasione,
Cli_CFPIVA, Ris_Nome, Ris_Citta,
Ris_Indirizzo, Men_Codice) con chiave Codice
Codice trigger:
CREATE OR UPDATE TRIGGER T_POSTIDISP
BEFORE INSERT ON Banchetti
FOR EACH ROW
DECLARE
  CURSOR c IS
      SELECT sum(b1.NumeroInvitati) as InvitatiBanchetti, r.NumeroPosti
as PostiDisponibili
      FROM Banchetti b1, Banchetti b2, Ristorante r
      WHERE (:new.Ris_Nome = r.Nome) AND (:new.Ris_Nome = b2.Ris_Nome)
AND (:new.Ris_Citta) = r.Citta AND (:new.Ris_Citta) = b2.Ris_Citta
AND (:new.Ris_Indirizzo) = r.Indirizzo AND (:new.Ris_Indirizzo) =
b2.Ris_Indirizzo
AND (:new.Data) = b2.Data
AND (:new.Codice) <> b2.Codice
      GROUP BY r.NumeroPosti;
begin
  FOR record IN c LOOP
    IF (record.InvitatiBanchetti > record.PostiDisponibili) THEN
	RAISE_APPLICATION_ERROR (-20001, 'Errore! Il ristorante non ha
abbastanza posti per  tutti i banchetti');
    END IF;
  END LOOP;
end;
Errori di compilazione:
ERRORE alla riga 2:
ORA-06550: riga 2, colonna 17:
PLS-00201: l'identificativo 'C' deve essere dichiarato
ORA-06550: riga 2, colonna 3:
PL/SQL: Statement ignored
Il cursore c l'ho dichiarato nella sezione DECLARE. Credo ci siano
problemi con la query. Forse un po' troppi join.
grazie ancora.
ciao

 da quel ristorante nella stessa data
Ancora non va.
Un aiutino?