hello I want to create a trigger in a nested table to verify that upon entering an author this is NOT under 18 years old. but it does not work
I tried this.
SET SERVEROUTPUT ON
CREATE OR REPLACE TRIGGER CHEQ_EDAD_AUTOR4
BEFORE INSERT OR UPDATE ON libros
FOR EACH ROW
DECLARE
ANIO_ACTUAL INT := TO_NUMBER(SYSDATE,'YYYY');
BEGIN
DBMS_OUTPUT.PUT_LINE('año actual' || TO_CHAR(ANIO_ACTUAL) - 'año nacimiento' || TO_CHAR(:NEW.autor.nacimiento.anio) );
IF ( ANIO_ACTUAL - :NEW.autor.nacimiento.anio ) <18 THEN
RAISE_APPLICATION_ERROR(-20001,'El autor debe ser mayor de 18 años.');
END IF;
END;
But when i create the trigger sql developer says
Error(4,9): PL/SQL: Statement ignored Error(4,110): PLS-00302:
component 'NACIMIENTO' must be declared Error(6,9): PL/SQL: Statement
ignored Error(6,40): PLS-00302: component 'NACIMIENTO' must be
declared
--Autor
CREATE TYPE nacimiento_type AS OBJECT(
ciudad VARCHAR2(20),
pais VARCHAR2(20),
anio INT
)
/
CREATE TYPE autores_type AS OBJECT(
id_autor NVARCHAR2(20),
nombres nombres_type,
nacimiento nacimiento_type
)
/
CREATE TYPE autores_tab AS TABLE OF autores_type;
/
--------------------------------------------------------------------------------
--Libro
CREATE TYPE libros_type AS OBJECT(
id_libro INT,
titulo NVARCHAR2(50),
editorial NVARCHAR2(50),
anio INT,
area NVARCHAR2(50),
autor autores_tab
)
/
CREATE TABLE libros OF libros_type(
id_libro PRIMARY KEY
)NESTED TABLE autor STORE AS autores_nested;
/
The inserted data are:
--Insertando libros
INSERT INTO LIBROS VALUES (1,'Base de datos relacionales','Rama',2001,'Informática',autores_tab());
INSERT INTO LIBROS VALUES (2,'Sistemas operativos: fundamentos básicos','Alfaomega',2009,'Informática',autores_tab());
COMMIT;
/
--Insertando autores de libros
INSERT INTO THE(
SELECT L.autor
FROM libros L
WHERE L.id_libro = 1)
VALUES (
autores_type('564212',nombres_type('Amanda','Miller','f'),nacimiento_type('Alemania','Colonia',1978))
);
COMMIT;
>>>>>HERE SHOULD HAVE PROBLEMS BECAUSE THE AGE IS 2012 so is only 5 years old.
INSERT INTO THE(
SELECT L.autor
FROM libros L
WHERE L.id_libro = 1)
VALUES (
autores_type('511111',nombres_type('miuu','dfgg','f'),nacimiento_type('arge','arge',2012))
);
COMMIT;
Autor is table type (not single object):
CREATE OR REPLACE TRIGGER CHEQ_EDAD_AUTOR4
BEFORE INSERT OR UPDATE ON libros
FOR EACH ROW
DECLARE
ANIO_ACTUAL INT := CAST(TO_CHAR(SYSDATE,'YYYY') AS INT);
BEGIN
IF :NEW.autor IS NOT EMPTY THEN
DBMS_OUTPUT.PUT_LINE('año actual' || TO_CHAR(ANIO_ACTUAL) - 'año nacimiento' || TO_CHAR(:NEW.autor(0).nacimiento.anio) );
IF ( ANIO_ACTUAL - :NEW.autor(0).nacimiento.anio ) <18 THEN
RAISE_APPLICATION_ERROR(-20001,'El autor debe ser mayor de 18 años.');
END IF;
END IF;
END;
/
Related
When I try to execute the stored procedure, all the parameters that I pass to it, appears "expression '(parameter)' cannot be used as an assignment target", I don't know what the problem is.
This is the stored procedure:
create or replace PROCEDURE INSTERT_UPDATE_EMPLEADO
(
CEDULA IN OUT INTEGER,
ID_CARGO IN OUT INTEGER,
ID_EMP IN OUT INTEGER,
NOMBRE IN OUT VARCHAR,
APELLIDO IN OUT VARCHAR,
FECHA_NAC IN OUT INTEGER,
FECHA_CON IN OUT INTEGER,
SALARIO IN OUT INTEGER
) AS
BEGIN
IF ID_EMP = 0 THEN
INSERT INTO EMPLEADO("CEDULA_EMPLEADO", "ID_CARGO", "EMPLEADO_ID", "NOMBRE", "APELLIDO", "FECHA_NAC", "FECHA_CONTRATO", "SALARIO")
VALUES (CEDULA, ID_CARGO, ID_EMP, NOMBRE, APELLIDO, FECHA_NAC, FECHA_CON, SALARIO);
ELSE
UPDATE EMPLEADO SET NOMBRE = NOMBRE, APELLIDO = APELLIDO, FECHA_NAC = FECHA_NAC, FECHA_CONTRATO = FECHA_CON, SALARIO = SALARIO,
CEDULA_EMPLEADO = CEDULA, ID_CARGO = ID_CARGO WHERE EMPLEADO_ID = ID_EMP;
END IF;
COMMIT;
END INSTERT_UPDATE_EMPLEADO;
Since you are going to insert or update the table, you need to create the table first.
If you already have the table, please ignore this step:
create table EMPLEADO
(
CEDULA NUMBER(5),
ID_CARGO NUMBER(5),
ID_EMP NUMBER(5),
NOMBRE VARCHAR2(20),
APELLIDO VARCHAR2(20),
FECHA_NAC NUMBER(5),
FECHA_CON NUMBER(5),
SALARIO NUMBER(5)
)
Then create the stored procedure:
CREATE OR REPLACE PROCEDURE INSTERT_UPDATE_EMPLEADO(
P_CEDULA IN EMPLEADO.CEDULA%TYPE,
P_ID_CARGO IN EMPLEADO.ID_CARGO%TYPE,
P_ID_EMP IN EMPLEADO.ID_EMP%TYPE,
P_NOMBRE IN EMPLEADO.NOMBRE%TYPE,
P_APELLIDO IN EMPLEADO.APELLIDO%TYPE,
P_FECHA_NAC IN EMPLEADO.APELLIDO%TYPE,
P_FECHA_CON IN EMPLEADO.FECHA_CON%TYPE,
P_SALARIO IN EMPLEADO.SALARIO%TYPE)
IS
BEGIN
IF P_ID_EMP = 0 THEN
INSERT INTO EMPLEADO("CEDULA_EMPLEADO", "ID_CARGO", "EMPLEADO_ID", "NOMBRE", "APELLIDO", "FECHA_NAC", "FECHA_CONTRATO", "SALARIO")
VALUES (P_CEDULA, P_ID_CARGO, P_ID_EMP, P_NOMBRE, P_APELLIDO, P_FECHA_NAC, P_FECHA_CON, P_SALARIO);
ELSE
UPDATE EMPLEADO
SET NOMBRE = P_NOMBRE,
APELLIDO = P_APELLIDO,
FECHA_NAC = P_FECHA_NAC,
FECHA_CONTRATO = P_FECHA_CON,
SALARIO = P_SALARIO,
CEDULA_EMPLEADO = P_CEDULA,
ID_CARGO = P_ID_CARGO
WHERE EMPLEADO_ID = P_ID_EMP;
END IF;
COMMIT;
END;
The problem not in the procedure itself, but in its interface. out and in out parameters write their values back as output. For example:
create table demo (id integer);
Procedure (creates without errors):
create or replace procedure insert_demo
( id in out demo.id%type )
as
begin
insert into demo (id) values (id);
end insert_demo;
Call fails, because the literal value 1 can't be updated with the out value returned by the procedure:
SQL> exec insert_demo(1)
BEGIN insert_demo(1); END;
*
ERROR at line 1:
ORA-06550: line 1, column 19:
PLS-00363: expression '1' cannot be used as an assignment target
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
If you are going to use out or in out parameters, you have to pass variables (SQL*Plus example below, though you could just call it from another procedure passing a normal PL/SQL variable):
SQL> var id number
SQL> exec :id := 1
PL/SQL procedure successfully completed.
ID
----------
1
SQL> exec insert_demo(:id)
PL/SQL procedure successfully completed.
ID
----------
1
The solution is therefore either to pass variables, or to change the parameter mode to in:
create or replace procedure insert_demo
( id in demo.id%type )
as
begin
insert into demo (id) values (id);
end insert_demo;
Test:
SQL> exec insert_demo(1)
PL/SQL procedure successfully completed.
It is generally good practice to avoid using column names for PL/SQL parameters and variables, for example by prefixing parameters with p_ and local variables with l_. Or if you must, you can use dot notation and the procedure name, e.g. insert_demo.id or instert_update_empleado.salario would specify the procedure parameter and not the table column. However, that is not the cause of the issue here.
(Also, your caps lock is on.)
On table "Types", the rows order shall be controled by the field "ordem".
After any data modifications(Delete, Insert or Update), the others rows should be ajusted to assure correct exbitions of the content.
To implement this funcionality, I tried to code a trigger to correct the values in two similar ways (I, II).
CREATE TABLE TYPES (
ID NUMBER PRIMARY KEY,
ARG_1 VARCHAR2(20) NOT NULL,
ARG_2 VARCHAR2(20) NOT NULL,
ORDEM NUMBER NOT NULL
);
-----------------------------------------------
-- I
-----------------------------------------------
CREATE OR REPLACE TRIGGER TGR_TYPES
AFTER INSERT OR UPDATE OR DELETE ON TYPES
DECLARE
V_NORDEM NUMBER := NEW.ORDEM;
CURSOR C_TYPES IS
SELECT ID, ORDEM
FROM TYPES
WHERE ORDEM >= V_NORDEM;
BEGIN
IF UPDATING OR INSERTING THEN
BEGIN
FOR R_TYPE IN C_TYPES LOOP
UPDATE TYPEA SET ORDEM = (ORDEM + 1) WHERE ID = R_TYPE.ID;
END LOOP;
END;
ELSE
DECLARE V_ORDEM NUMBER := 0;
BEGIN
FOR R_TYPE IN C_TYPES LOOP
UPDATE OSP_TP_ADDR_COMPLEMENTOS SET ORDEM = (V_ORDEM + 1) WHERE ID = R_COMPLEMENTO.ID;
END LOOP;
END;
END IF;
END;
/*
ERROR ON COMPILE:
ORA-04082: referências NEW ou OLD não permitidas nos gatilhos de nível de tabela
04082. 00000 - "NEW or OLD references not allowed in table level triggers"
*Cause: The trigger is accessing "new" or "old" values in a table trigger.
*Action: Remove any new or old references.
*/
-----------------------------------------------
-- II
-----------------------------------------------
CREATE OR REPLACE
TRIGGER TRG_TYPES
AFTER INSERT OR UPDATE OR DELETE ON TYPES
FOR EACH ROW
BEGIN
IF UPDATING OR INSERTING THEN
BEGIN
FOR TP IN (
SELECT *
FROM TYPES
WHERE ORDEM >= :NEW.ORDEM
) LOOP
UPDATE TYPES SET ORDEM = (ORDEM + 1) WHERE ID = TP.ID;
COMMIT;
END LOOP;
END;
ELSE
DECLARE V_ORDEM NUMBER := 0;
BEGIN
FOR TP IN (
SELECT *
FROM TYPES
ORDER BY ORDEM
) LOOP
UPDATE TYPES SET ORDEM = (V_ORDEM + 1) WHERE ID = TP.ID;
END LOOP;
END;
END IF;
END;
/*
ERROR ON UPDATE:
UPDATE TYPES
SET ORDEM = 14
WHERE ID=26
Relatório de erros -
ORA-04091: a tabela TYPES é mutante; talvez o gatilho/função não possa localizá-la
ORA-06512: em "", line 9
ORA-04088: erro durante a execução do gatilho ''
*/
I expect one solution to assure the trigger operation or other approach to the integrity of the order field. I have thinking about tring the Index-Organized Table structure, but not sure.
I am trying to create a table in apex5 with reference having foreign key from another table and that foreign key column is populated. But to create is returning the error ORA- 00922: missing or invalid option, already checked and not noticed any error naming what can is going wrong? The following code:
CREATE TABLE "IMAGEM_ICONE_SISTEMA"
( "COD" NUMBER NOT NULL ENABLE,
"COD_SISTEMA" NUMBER(6,0) NOT NULL ENABLE,
"NOME" VARCHAR2(55),
"ARQUIVO_IMAGEM" BLOB,
"MIMETYPE" VARCHAR2(255),
"FILENAME" VARCHAR2(400),
"IMG_LAST_UPDATE" TIMESTAMP (6) WITH LOCAL TIME ZONE,
"UPDATED_BY" VARCHAR2(55),
"TEXTO_DESCRICAO" VARCHAR2(55),
"LINK" VARCHAR2(2000),
"NUM_ORDEM" NUMBER(6,0),
CONSTRAINT "IMAGEM_ICONE_SISTEM_PK" PRIMARY KEY ("COD") USING INDEX ENABLE)
/
ALTER TABLE "IMAGEM_ICONE_SISTEMA" ADD CONSTRAINT "IMAGEM_ICONE_SISTEMA_FK" FOREIGN KEY ("COD_SISTEMA")
REFERENCES "APEX_SISTEMA" ("COD") ON DELETE CASCADE ENABLE
/
CREATE INDEX "IMAGEM_ICONE_SISTEMA_I2" ON "IMAGEM_ICONE_SISTEMA" ("COD_SISTEMA")
/
CREATE OR REPLACE EDITIONABLE TRIGGER "BI_IMAGEM_ICONE_SISTEMA" before insert or update on IMAGEM_ICONE_SISTEMA
for each row
begin
if :new.COD is null then
select to_number(sys_guid(),'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') into :new.cod from dual;
end if;
if inserting then
:new.img_last_update := localtimestamp;
:new.updated_by := nvl(wwv_flow.g_user,user);
elsif updating and :new.filename is not null and nvl(dbms_lob.getlength(:new.arquivo_imagem),0) > 15728640 then raise_application_error(-20000, 'O tamanho do arquivo enviado foi maior do que 15MB . Faça o upload de um arquivo de tamanho menor.');
end if;
if (inserting or updating) and :new.filename is not null and nvl(:new.mimetype,'NULL') not like 'image%' then
raise_application_error(-20000, 'O arquivo enviado não é uma imagem. Faça o upload de um arquivo de imagem.');
end if;
if inserting or updating then
:new.img_last_update := localtimestamp;
:new.updated_by := nvl(wwv_flow.g_user,user);
end if;
end;
/
ALTER TRIGGER "BI_IMAGEM_ICONE_SISTEMA" ENABLE
/
This is my query. A Trigger which automatically stores in a separate table called ‘ExcellentSale’ the Sales Agent
name, car model and manufacturer name, each time the agreed price of a
SalesTransaction is more than 20% of the car’s asking price. (Note: You need to create
the ‘ExcellentSale’ table before implementing this trigger. To create the primary key, use a
sequence that starts at 1 and increments by 1). It shows error like this
ERROR at line 23: PL/SQL: ORA-00942: table or view does not exist
1. create or replace trigger filltable
2. after insert on salestransaction
3. for each row
4. declare
The code for the trigger is:
create or replace trigger filltable
after insert on salestransaction
for each row
declare
aname varchar2(25);
modname varchar2(25);
manfname varchar2(25);
askpr number;
agrpr number;
begin
select sa.name,m.name,mf.name
into aname,modname,manfname
from manufacturer mf,model m, car c, salestransaction st, salesagent sa
where mf.manufacturerid = m.manufacturerid and
m.modelno = c.modelno and
c.vin = st.vin and
st.agentid = sa.agentid;
select askingprice,agreedprice
into askpr,agrpr
from car c,salestransaction st
where c.VIN = St.vin;
if(agrpr > askpr*1.2) then
insert into excellentsales values(agent_seq.nextval,aname,modname,manfname);
end if;
end filltable;
/
create table excellentsales
(agentid varchar2(5) not null,
agentname varchar2(25),
carmodel varchar2(25),
mfname varchar2(25),
primary key(agentid))
CREATE SEQUENCE agent_seq START WITH 1 INCREMENT BY 1;
You don't need to query SALESTRANSACTION within a row trigger on SALESTRANSACTION - you should instead be using the :NEW values on the SALESTRANSACTION row for which the trigger was invoked. I suggest rewriting your trigger as:
create table excellentsales
(EXCELLENTSALES_ID NUMBER
CONSTRAINT PK_EXCELLENTSALES
PRIMARY KEY
USING INDEX,
agentid varchar2(5) not null,
agentname varchar2(25),
carmodel varchar2(25),
mfname varchar2(25))
CREATE SEQUENCE EXCELLENTSALES_SEQ
START WITH 1
INCREMENT BY 1;
create or replace trigger filltable
after insert on salestransaction
for each row
declare
aname varchar2(25);
modname varchar2(25);
manfname varchar2(25);
askpr number;
agrpr number;
begin
SELECT m.NAME, mf.NAME, c.ASKINGPRICE
INTO modname, manfname, askpr
FROM CAR c
INNER JOIN MODEL m
ON m.MODELNO = c.MODELNO
INNER JOIN MANUFACTURER mf
ON mf.MANUFACTURERID = m.MANUFACTURERID
WHERE c.VIN = :NEW.VIN;
SELECT sa.NAME
INTO aname
FROM SALESAGENT sa
WHERE sa.AGENTID = :NEW.AGENTID;
agrpr := :NEW.AGREEDPRICE;
if agrpr > askpr * 1.2 then
insert into excellentsales (EXCELLENTSALES_ID, AGENTID, AGENTNAME, CARMODEL, MFNAME)
values(EXCELLENTSALES_SEQ.nextval, :NEW.AGENTID, aname, modname, manfname);
end if;
end filltable;
I also redesigned your EXCELLENTSALES table to include a primary key which is not the AGENTID. As originally designed EXCELLENTSALES did not record the actual AGENTID (which should apparently be coming from SALESTRANSACTION), which in the real world might be needed, for example, for paying commissions.
this is my very first question, I'm new here so I hope I'm asking well in the right topic... etc.
I'm trying with a trigger wich catch information from one table, compares some data from this table and if a condition is true then the trigger have to store the information changing some values. There are my tables and the trigger. I need this trigger to store larger tables with a lot of columns and a lot more information but this is just a test, please help! :'(
create table datos_prueba(
nombre varchar2(10) primary key,
numero number(3),
mensaje varchar(30),
fecha date);
create table store_datos_prueba(
nombre varchar(20) primary key,
numero number(5),
mensaje varchar(30),
fecha date);
And this is the trigger, I worte it but it's wrong...
create or replace trigger tgr_trigger_prueba
after insert on datos_prueba
for each row
declare
cambio_numero number;
begin
if :datos_prueba.numero <= 5 then
insert into store_datos_prueba (nombre,numero,mensaje,fecha) values(:datos_prueba.nombre,666,:datos_prueba.mensaje,:datos_prueba.fecha);
else
insert into store_datos_prueba (nombre,numero,mensaje,fecha) values(:datos_prueba.nombre,777,:datos_prueba.mensaje,:datos_prueba.fecha);
end if;
end;
You have to use old or new to refer the row value. Not the table name.
create or replace trigger tgr_trigger_prueba
after insert on datos_prueba
for each row
declare
cambio_numero number;
begin
if :new.numero <= 5 then
insert into store_datos_prueba (nombre,numero,mensaje,fecha) values(:new.nombre,666,:new.mensaje,:new.fecha);
else
insert into store_datos_prueba (nombre,numero,mensaje,fecha) values(:new.nombre,777,:new.mensaje,:new.fecha);
end if;
end;
/
More on Triggers