Utworzenie triggera w Oracle

0

Cześć!
Chcę stworzyć triggera i cały czas pokazuje mi się błąd. Poniżej kod:
create or replace TRIGGER T_AFTER_INSERT_1
AFTER INSERT ON USL_B
FOR EACH ROW
begin
update POR_B
SET ST_POR_B = 'zajety'
WHERE
(SELECT ID_POR_B, ST_POR_B, USL_B.POR_B_ID_POR_B FROM POR_B
JOIN USL_B ON POR_B.ID_POR_B = USL_B.POR_B_ID_POR_B
WHERE ST_POR_B = 'wolny'
AND POR_B.ID_POR_B = USL_B.POR_B_ID_POR_B);

end;

I błędy, jakie mi się pojawiają:
Error(5,1): PL/SQL: SQL Statement ignored
Error(11,63): PL/SQL: ORA-00936: missing expression

Ktoś wie może, jak ten problem rozwiązać?

0

WHERE co?

0

W SAPie piszesz? Na prawdę masz takie nazwy kolumn? Prawdopodobnie cos mocno pokrecilas. Te bledy występują wtedy kiedy brakuje przecinków, srednikow. Przynajmniej w moim oracle ale tam sa nazwy takie ze wiem co chce zrobic. Update przyjrzalam sie. To nie jest tak ze w świecie stosujesz sobie konwencje jakie chcesz. Nie masz w części prefiksów. Jesli joinujesz musisz miec prefiksy, żeby wiedzieć o ktora kolumnę Ci chodzi

0

W Oracle :D Ja wiem co chcę zrobić, nie wiem tylko jak :D Może teraz będzie to bardziej czytelne:

create or replace TRIGGER T_AFTER_STATUS_PORTU_BBB_1
AFTER INSERT ON USŁUGA_BBB
FOR EACH ROW

begin
update PORTY_BBB
SET STATUS_PORTU_BBB = 'zajety'
WHERE

(SELECT ID_PORT_BBB, STATUS_PORTU_BBB, -- to dot. tabeli PORTY_BBB

USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB -- dot. tabeli USŁUGA_BBB

FROM PORTY_BBB
JOIN USŁUGA_BBB
ON PORTY_BBB.ID_PORT_BBB = USŁUGA_BBB**.PORTY_BBB_ID_PORT_BBB**
WHERE STATUS_PORTU_BBB = 'wolny' -- dot. tabeli PORTY_BBB
AND PORTY_BBB.ID_PORT_BBB = USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB);

end;

@kate87 - kolumny mam podane, zaznaczyłam pogrubioną czcionką. Gdzie mogę mieć jeszcze błąd?

0
Paulina1 napisał(a):

Może teraz będzie to bardziej czytelne:

Nie będzie - to jest jakiś koszmar a nie formatowanie - wejdź sobie np. na http://poorsql.com i tam sformatuj

UPDATE PORTY_BBB
SET STATUS_PORTU_BBB = 'zajety'
WHERE (
    SELECT ID_PORT_BBB
      ,STATUS_PORTU_BBB
      ,-- to dot. tabeli PORTY_BBB
      USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB -- dot. tabeli USŁUGA_BBB
    FROM PORTY_BBB
    INNER JOIN USŁUGA_BBB ON PORTY_BBB.ID_PORT_BBB = USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB
    WHERE STATUS_PORTU_BBB = 'wolny' -- dot. tabeli PORTY_BBB
      AND PORTY_BBB.ID_PORT_BBB = USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB
    )

i odpowiedz na pytanie @Marcin.Miga - WHERE i co dalej?

0

OK, triggery przeszły, jednak na nic mi to, ponieważ nie działają. Przy próbie dodania danych do tabeli jest błąd.

One error saving changes to table "EWIDENCJA"."USŁUGA_BBB":
Row 3: ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "EWIDENCJA.T_BEFORE_INSERT_USLUGA_BBB", line 4
ORA-04088: error during execution of trigger 'EWIDENCJA.T_BEFORE_INSERT_USLUGA_BBB'
ORA-06512: at line 1

CREATE
	OR replace TRIGGER t_BEFORE_INSERT_USLUGA_BBB before

INSERT ON USŁUGA_BBB
FOR each row

DECLARE wynik_1 NUMERIC;

BEGIN
	SELECT PORTY_BBB_ID_PORT_BBB
	INTO wynik_1
	FROM USŁUGA_BBB
	JOIN PORTY_BBB ON USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB = PORTY_BBB.ID_PORT_BBB
	WHERE PORTY_BBB.STATUS_PORTU_BBB = 'zajety'
		AND USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB = PORTY_BBB.ID_PORT_BBB;

	IF :new.ID_BBB IS NULL then
		SELECT seq_autoincrement.nextval
		INTO :new.ID_BBB
		FROM dual;
END IF ;

:new.ID_USLUGI_BBB : = UPPER(:new.ID_USLUGI_BBB);
:new.MAC_ADRES : = UPPER(:new.MAC_ADRES);

IF 
:new.PORTY_BBB_ID_PORT_BBB = wynik_1 then RAISE_APPLICATION_ERROR(- 20001, 'Podany port jest zajęty.');
END IF ;
END;
0

Błąd masz z powodu SELECT INTO w tym zapytaniu:

 SELECT PORTY_BBB_ID_PORT_BBB
    INTO wynik_1
    FROM USŁUGA_BBB
    JOIN PORTY_BBB ON USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB = PORTY_BBB.ID_PORT_BBB
    WHERE PORTY_BBB.STATUS_PORTU_BBB = 'zajety'
        AND USŁUGA_BBB.PORTY_BBB_ID_PORT_BBB = PORTY_BBB.ID_PORT_BBB;

Spróbuj wykonać to zapytanie poza triggerem i zobaczysz że masz więcej wierszy niż jeden.

Dodatkowo przy takiej konstrukcji i braku wyników z zapytania dostaniesz bład ORA-... Nie znaleziono danych.
Musisz to rozwiązać inaczej.

0

OK, dzięki za podpowiedź, kombinuję dalej :)

EDIT:
Zmodyfikowałam trigger:

create or replace trigger t_BEFORE_INSERT_USLUGA_BBB
before insert on USŁUGA_BBB
for each row  

DECLARE wynik_1 numeric;

begin
SELECT ID_PORT_BBB INTO wynik_1 FROM PORTY_BBB
WHERE ID_PORT_BBB = :NEW.PORTY_BBB_ID_PORT_BBB
AND STATUS_PORTU_BBB = 'zajety';

if :new.ID_BBB is null then 
SELECT seq_autoincrement.nextval into :new.ID_BBB from dual;
end if;

:new.ID_USLUGI_BBB := UPPER(:new.ID_USLUGI_BBB); 
:new.MAC_ADRES := UPPER(:new.MAC_ADRES); 

if :new.PORTY_BBB_ID_PORT_BBB = wynik_1 then
RAISE_APPLICATION_ERROR(-20001, 'Podany port jest zajęty.');
end if;
end;

i wciąż pojawia się błąd przy próbie wstawienia (prawidłowych) danych do tabeli:

One error saving changes to table "EWIDENCJA"."USŁUGA_BBB":
Row 3: ORA-01403: no data found
ORA-01403: no data found
ORA-06512: at "EWIDENCJA.T_BEFORE_INSERT_USLUGA_BBB", line 4
ORA-04088: error during execution of trigger 'EWIDENCJA.T_BEFORE_INSERT_USLUGA_BBB'
ORA-06512: at line 1

Generalnie jeśli podstawię takie dane, żeby wywołać drugiego IF-a:
if :new.PORTY_BBB_ID_PORT_BBB = wynik_1 then
RAISE_APPLICATION_ERROR(-20001, 'Podany port jest zajęty.');

zwraca
One error saving changes to table "EWIDENCJA"."USŁUGA_BBB":
Row 3: ORA-20001: Podany port jest zajęty.
ORA-06512: at "EWIDENCJA.T_BEFORE_INSERT_USLUGA_BBB", line 16
ORA-04088: error during execution of trigger 'EWIDENCJA.T_BEFORE_INSERT_USLUGA_BBB'
ORA-06512: at line 1.

0

No tak ponieważ jeśli zapytanie:

 SELECT ID_PORT_BBB INTO wynik_1 FROM PORTY_BBB
WHERE ID_PORT_BBB = :NEW.PORTY_BBB_ID_PORT_BBB
AND STATUS_PORTU_BBB = 'zajety';

nie znajdzie dopasowania to rzuca tak jak pisałem wcześniej NO DATA FOUND.

Musisz opakować to zapytanie w blok BEGIN .... END z łapaniem wyjątków typu NO_DATA_FOUND i TOO_MANY_ROWS.
Czyli coś w stylu:

BEGIN
SELECT ID_PORT_BBB INTO wynik_1 FROM PORTY_BBB
WHERE ID_PORT_BBB = :NEW.PORTY_BBB_ID_PORT_BBB
AND STATUS_PORTU_BBB = 'zajety';

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    NULL; -- Bo jak rozumiem, sytuacja w której nie ma zajętego portu jak aktualnie wstawiany ID to jest ok
  WHEN TOO_MANY_ROWS THEN
   RAISE_APPLICATION_ERROR(-20001, 'Coś jest nie tak. Mamy więcej niż jeden zajęty port o tym samym ID');
END;

EDIT:
A jeszcze lepiej jakbyś zmieniła zapytanie na:

 
SELECT count(ID_PORT_BBB) INTO wynik_1 FROM PORTY_BBB
WHERE ID_PORT_BBB = :NEW.PORTY_BBB_ID_PORT_BBB
AND STATUS_PORTU_BBB = 'zajety';

i później ifologia czyli

IF wynik_1=1 THEN
  RAISE_APPLICATION_ERROR(-20001, 'Podany port jest zajęty');
ELSIF wynik_1>1 THEN
  RAISE_APPLICATION_ERROR(-20001, 'Coś jest nie tak. Mamy więcej niż jeden zajęty port o tym samym ID');
END IF; 
/*Możemy przejść dalej ponieważ nie ma zajętych portów o podanym id*/

I dodatkowo powinniśmy zabezpieczyć sytuację, w której :NEW.PORTY_BBB_ID_PORT_BBB bedzie NULL

0

Dzięki za pomoc! Pokombinowałam i w końcu przeszło i działa :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1