Related
I have table for ddl logs. And in this table I also want to see which code was exactly done. How can I put it into sql_tt column? Can you prompt me with this?
CREATE TABLE AAUDIT_DDL (
d date,
OSUSER varchar2(255),
CURRENT_USER varchar2(255),
HOST varchar2(255),
IP_ADDRESS VARCHAR2(100 CHAR),
TERMINAL varchar2(255),
owner varchar2(30),
OBJECT_TYPE varchar2(30),
OBJECT_NAME varchar2(30),
DDL_TYPE varchar2(30),
SQL_TT varchar(100));
and trigger
create or replace trigger aaudit_ddl after ddl on DATABASE
begin
if (ora_sysevent='REVOKE')
then
null; -- I do not care about REVOKE
else
insert into aaudit_ddl(d, osuser,current_user,host,ip_address,terminal,owner,OBJECT_TYPE,OBJECT_NAME,DDL_TYPE,SQL_TT)
values(
sysdate,
sys_context('USERENV','OS_USER') ,
sys_context('USERENV','CURRENT_USER') ,
sys_context('USERENV','HOST') ,
SYS_CONTEXT('USERENV','IP_ADDRESS'),
sys_context('USERENV','TERMINAL') ,
ora_dict_obj_owner,
ora_dict_obj_type,
ora_dict_obj_name,
ora_sysevent,
ora_sql_txt
);
end if;
end;
/
Documentation suggests different approach to ora_sql_txt: as function expects IN parameter (which is an integer, representing number of elements in PL/SQL table), you should
CREATE TABLE event_table (col VARCHAR2(2030));
DECLARE
sql_text ora_name_list_t;
n PLS_INTEGER;
v_stmt VARCHAR2(2000);
BEGIN
n := ora_sql_txt(sql_text);
FOR i IN 1..n LOOP
v_stmt := v_stmt || sql_text(i);
END LOOP;
INSERT INTO event_table VALUES ('text of triggering statement: ' || v_stmt);
END;
This is how I have mine setup and it works fine.
--Table will be created by sys user with tbs_audit as tablespace as default tablespace for audit table AUDIT_DDL
CREATE TABLE AUDIT_DDL (
DDL_DATE date,
OSUSER varchar2(255),
CURRENT_USER varchar2(255),
HOST varchar2(255),
TERMINAL varchar2(255),
IP_ADDRESS VARCHAR2(100),
module varchar2(100),
owner varchar2(30),
type varchar2(30),
name varchar2(30),
sysevent varchar2(30),
sql_txt varchar2(4000) )
tablespace tbs_audit ;
--- Trigger will be created at sys user, so that all statements will be captured in any schema in the database
create or replace trigger
sys.audit_ddl_trg after ddl on database
declare
sql_text ora_name_list_t;
stmt VARCHAR2(4000) := '';
n number;
begin
n:=ora_sql_txt(sql_text);
for i in 1..n
loop
stmt:=substr(stmt||sql_text(i),1,4000);
end loop;
insert into audit_ddl(
DDL_DATE,osuser,
current_user,host,
terminal,
ip_address,module,
owner,
type,name,sysevent,sql_txt)
values(
sysdate,
sys_context('USERENV','OS_USER') ,
sys_context('USERENV','CURRENT_USER') ,
sys_context('USERENV','HOST') ,
sys_context('USERENV','TERMINAL') ,
UTL_INADDR.get_host_name('USERENV'),
sys_context('USERENV','MODULE') ,
ora_dict_obj_owner,
ora_dict_obj_type,
ora_dict_obj_name,
ora_sysevent,
stmt
);
end;
/
-- Sql Query can be used to lookup the captured ddl in the audit_ddl table.
col type format a10
col name format a10
col host format a16
col IP_ADDRESS format a10
col terminal format a20
col owner format a15
col sql_txt format a20
col SYSEVENT format a10
col CURRENT_USER format a10
col osuser format a10
select * from AUDIT_DDL;
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 7 years ago.
Improve this question
I have the following small function that does not compile:
CREATE OR REPLACE PROCEDURE insertarVentas(ID NUMBER, IDCliente NUMBER, nombre VARCHAR2, calle VARCHAR2, poblacion VARCHAR2, cp NUMBER, provincia VARCHAR2, dni VARCHAR2,
telef1 VARCHAR2, telef2 VARCHAR2, telef3 VARCHAR2, fechaventa date, numerolinea NUMBER, IDProducto NUMBER, descripcion VARCHAR2, pvp NUMBER, stockactual NUMBER, cantidad NUMBER) AS
BEGIN
INSERT INTO TABLA_VENTAS VALUES (ID, TIP_CLIENTE(IDCliente, nombre, TIP_DIRECCION(calle, poblacion, cp, provincia), dni, TIP_TELEFONOS(telef1, telef2, telef3)), fechaventa,
TIP_LINEAS_VENTA(numerolinea, TIP_PRODUCTO(IDProducto, descripcion, pvp, stockactual), cantidad));
END insertarVentas;
The compiler gives me the following errors:
Error at line 4: PL/SQL: SQL Statement ignored
2. telef1 VARCHAR2, telef2 VARCHAR2, telef3 VARCHAR2, fechaventa date, numerolinea NUMBER, IDProducto NUMBER, descripcion VARCHAR2, pvp NUMBER, stockactual NUMBER, cantidad NUMBER) AS
3. BEGIN
4. INSERT INTO TABLA_VENTAS VALUES (ID, TIP_CLIENTE(IDCliente, nombre, TIP_DIRECCION(calle, poblacion, cp, provincia), dni, TIP_TELEFONOS(telef1, telef2, telef3)), fechaventa,
5. TIP_LINEAS_VENTA(numerolinea, TIP_PRODUCTO(IDProducto, descripcion, pvp, stockactual), cantidad));
6. END insertarVentas;
This is an insert into a object table, this is the code that table
CREATE TABLE TABLA_VENTAS OF TIP_VENTA(
IDVENTA PRIMARY KEY
)NESTED TABLE LINEAS STORE AS TABLA_LINEAS;
CREATE TYPE TIP_VENTA AS OBJECT(
IDVENTA NUMBER,
IDCLIENTE REF TIP_CLIENTE,
CREATE TYPE TIP_CIENTE AS OBJECT(
IDCLIENTE NUMBER,
NOMBRE VARCHAR2(50),
DIREC TIP_DIRECCION,
CREATE TYPE TIP_DIRECCION AS OBJECT(
CALLE VARCHAR2(50),
POBLACION VARCHAR2(50),
CODPOSTAL NUMBER(5),
PROVINCIA VARCHAR2(40)
);
NIF VARCHAR2(9),
TELEF TIP_TELEFONOS
CREATE TYPE TIP_TELEFONOS AS VARRAY(3) OF VARCHAR2(15);
);
FECHAVENTA DATE,
LINEAS TIP_LINEAS_VENTA,
CREATE TYPE TIP_LINEAVENTA AS OBJECT(
NUMEROLINEA NUMBER,
IDPRODUCTO REF TIP_PRODUCTO,
CREATE TYPE TIP_PRODUCTO AS OBJECT(
IDPRODUCTO NUMBER,
DESCRIPCION VARCHAR2(80),
PVP NUMBER,
STOCKACTUAL NUMBER
);
CANTIDAD NUMBER
);
CREATE TYPE TIP_LINEAS_VENTA AS TABLE OF TIP_LINEAVENTA;
);
What is causing this error and how can I fix it?
The PL/SQL: SQL Statement ignored message is usually just the top of the error stack and a following line will indicate what the actual issue is.
Having untangled your object creation statements and got them in an order that lets them all compile (and fixed at least one typo, and guess that a dangling comma was also a typo), creating your procedure gets:
LINE/COL ERROR
-------- ------------------------------------
4/1 PL/SQL: SQL Statement ignored
4/13 PL/SQL: ORA-00947: not enough values
You've defined TIP_VENTA with five fields:
CREATE TYPE TIP_VENTA AS OBJECT(
IDVENTA NUMBER,
IDCLIENTE REF TIP_CLIENTE,
FECHAVENTA DATE,
LINEAS TIP_LINEAS_VENTA,
CANTIDAD NUMBER
);
But the object you create during your insert only has four values (reformatted to make it a bit more readable):
INSERT INTO TABLA_VENTAS VALUES (
ID,
TIP_CLIENTE(
IDCliente,
nombre,
TIP_DIRECCION(calle, poblacion, cp, provincia),
dni,
TIP_TELEFONOS(telef1, telef2, telef3)
),
fechaventa,
TIP_LINEAS_VENTA(
numerolinea,
TIP_PRODUCTO(IDProducto, descripcion, pvp, stockactual),
cantidad
)
);
You've got cantidad inside the TIP_LINEAS_VENTA() constructor call, instead of after it:
INSERT INTO TABLA_VENTAS VALUES (
ID,
TIP_CLIENTE(
IDCliente,
nombre,
TIP_DIRECCION(calle, poblacion, cp, provincia),
dni,
TIP_TELEFONOS(telef1, telef2, telef3)
),
fechaventa,
TIP_LINEAS_VENTA(
numerolinea,
TIP_PRODUCTO(IDProducto, descripcion, pvp, stockactual)
),
cantidad
);
But that now gets:
LINE/COL ERROR
-------- ------------------------------------------------------------------
9/1 PL/SQL: SQL Statement ignored
20/5 PL/SQL: ORA-00932: inconsistent datatypes: expected UDT got NUMBER
The fourth field of the TIP_VENTA is type TIP_LINEAS_VENTA, so you need to have a TIP_LINEAVENTA within that table constructor:
TIP_LINEAS_VENTA(
TIP_LINEAVENTA(
numerolinea,
TIP_PRODUCTO(IDProducto, descripcion, pvp, stockactual)
)
Which then gets:
LINE/COL ERROR
-------- -----------------------------------------------------------------------------------------------------------------
9/1 PL/SQL: SQL Statement ignored
22/7 PL/SQL: ORA-00932: inconsistent datatypes: expected X.TIP_PRODUCTO got REF X.TIP_PRODUCTO
... because you're using actual objects instead of REFs to them, as the other type definitions expect. You'll need to decide whether to make them actual objects or fix the REFs...
I think the issue is that you're trying to insert into a table of an object something that isn't an object.
I've split out your object type populations into variables (rather than leaving them nested inside the insert statement as you did) which hopefully enables you to see what it is you're actually trying to insert:
create or replace procedure insertarventas (id number,
idcliente number,
nombre varchar2,
calle varchar2,
poblacion varchar2,
cp number,
provincia varchar2,
dni varchar2,
telef1 varchar2,
telef2 varchar2,
telef3 varchar2,
fechaventa date,
numerolinea number,
idproducto number,
descripcion varchar2,
pvp number,
stockactual number,
cantidad number)
as
v_tip_venta tip_venta;
v_tip_cliente tip_cliente;
v_tip_direccion tip_direccion;
v_tip_telefonos tip_telefonos;
v_tip_lineaventa tip_lineaventa;
v_tip_lineas_venta tip_lineas_venta;
v_tip_producto tip_producto;
begin
v_tip_direccion := tip_direccion (calle,
poblacion,
cp,
provincia);
v_tip_telefonos := tip_telefonos (telef1,
telef2,
telef3);
v_tip_cliente := tip_cliente (idcliente,
nombre,
v_tip_direccion,
dni,
v_tip_telefonos);
v_tip_producto := tip_producto (idproducto,
descripcion,
pvp,
stockactual);
v_tip_lineaventa := tip_lineaventa (numerolinea,
v_tip_producto,
cantidad);
v_tip_lineas_venta := tip_lineas_venta (v_tip_lineaventa);
-- this is the step you were missing
v_tip_venta := tip_venta (id,
v_tip_cliente,
fechaventa,
v_tip_lineas_venta);
insert into tabla_ventas
values (v_tip_venta);
end insertarventas;
/
N.B. untested.
Ok, the presence of the REFs in the object type descriptions is what is causing the problems. However, I don't think it's necessary to use REF (not to mention that I couldn't work out how to make the code work with them! *{;-) ), so here is a working test case without the REFs:
drop procedure insertarventas;
drop table tabla_ventas;
drop type tip_venta;
drop type tip_lineas_venta;
drop type tip_lineaventa;
drop type tip_producto;
drop type tip_cliente;
drop type tip_telefonos;
drop type tip_direccion;
create type tip_direccion as object (calle varchar2(50),
poblacion varchar2(50),
codpostal number(5),
provincia varchar2(40));
create type tip_telefonos as varray(3) of varchar2(15);
create type tip_cliente as object (idcliente number,
nombre varchar2(50),
direc tip_direccion,
nif varchar2(9),
telef tip_telefonos);
create type tip_producto as object (idproducto number,
descripcion varchar2(80),
pvp number,
stockactual number);
create type tip_lineaventa as object (numerolinea number,
idproducto tip_producto,
cantidad number);
create type tip_lineas_venta as table of tip_lineaventa;
create type tip_venta as object (idventa number,
idcliente tip_cliente,
fechaventa date,
lineas tip_lineas_venta);
create table tabla_ventas of tip_venta (idventa primary key)
nested table lineas store as tabla_lineas;
create or replace procedure insertarventas (id number,
idcliente number,
nombre varchar2,
calle varchar2,
poblacion varchar2,
cp number,
provincia varchar2,
dni varchar2,
telef1 varchar2,
telef2 varchar2,
telef3 varchar2,
fechaventa date,
numerolinea number,
idproducto number,
descripcion varchar2,
pvp number,
stockactual number,
cantidad number)
as
v_tip_venta tip_venta;
v_tip_cliente tip_cliente;
v_tip_direccion tip_direccion;
v_tip_telefonos tip_telefonos;
v_tip_lineaventa tip_lineaventa;
v_tip_lineas_venta tip_lineas_venta;
v_tip_producto tip_producto;
begin
v_tip_direccion := tip_direccion (calle,
poblacion,
cp,
provincia);
v_tip_telefonos := tip_telefonos (telef1,
telef2,
telef3);
v_tip_cliente := tip_cliente (idcliente,
nombre,
v_tip_direccion,
dni,
v_tip_telefonos);
v_tip_producto := tip_producto (idproducto,
descripcion,
pvp,
stockactual);
v_tip_lineaventa := tip_lineaventa (numerolinea,
v_tip_producto,
cantidad);
v_tip_lineas_venta := tip_lineas_venta (v_tip_lineaventa);
-- this is the step you were missing
v_tip_venta := tip_venta (id,
v_tip_cliente,
fechaventa,
v_tip_lineas_venta);
insert into tabla_ventas
values (v_tip_venta);
end insertarventas;
/
I'm trying to create a stored procedure to insert values into the EMPLOYEE TABLE.
When I try and execute the procedure with values it throws up an error. Please could you help? Thank you in advance.
Stored Procedure ----
create or replace PROCEDURE CREATE_EMP
(empid IN EMPLOYEE.EMP_ID%TYPE,
firstname IN EMPLOYEE.FIRST_NAME%TYPE,
surname IN EMPLOYEE.SURNAME%TYPE,
address IN EMPLOYEE.ADDRESS%TYPE,
city IN EMPLOYEE.CITY%TYPE,
county IN EMPLOYEE.COUNTY_STATE%TYPE,
postcode IN EMPLOYEE.POSTCODE_ZIP%TYPE,
country IN EMPLOYEE.COUNTRY%TYPE,
jobtitle IN EMPLOYEE.JOB_TITLE%TYPE,
startdate IN EMPLOYEE.START_DATE%TYPE,
enddate IN EMPLOYEE.END_DATE%TYPE)
AS
BEGIN
INSERT INTO EMPLOYEE
VALUES(empid, firstname, surname, address, city, county, postcode, country, jobtitle, startdate, enddate);
END CREATE_EMP;
Execute command ---
EXECUTE CREATE_EMP(58,'John','Testy','Here Lane','Himble','UK','Skipper',2015/02/02,2017/02/02);
Error Message ----
Error starting at line : 1 in command -
EXECUTE CREATE_EMP(58,'John','Testy','Here Lane','Himble','UK','Skipper',2015/02/02,2017/02/02)
Error report -
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'CREATE_EMP'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Table -----
EMP_ID NUMBER(8,0)
FIRST_NAME VARCHAR2(30 BYTE)
SURNAME VARCHAR2(30 BYTE)
ADDRESS VARCHAR2(50 BYTE)
CITY VARCHAR2(30 BYTE)
COUNTY_STATE VARCHAR2(30 BYTE)
POSTCODE_ZIP VARCHAR2(10 BYTE)
COUNTRY VARCHAR2(5 BYTE)
JOB_TITLE VARCHAR2(20 BYTE)
START_DATE DATE
END_DATE DATE
Error message says:
PLS-00306: wrong number or types of arguments in call to 'CREATE_EMP'
I've mapped your given arguments to methods required arguments:
empid = 58
firstname = 'John'
surname = 'Testy'
address = 'Here Lane'
city = 'Himble'
county
postcode
country = 'UK'
jobtitle = 'Skipper'
startdate = 2015/02/02
enddate = 2017/02/02
Since no argument has default value, you simply miss 2 arguments in the call, as error message said.
EDIT: I've found the solution:
Execute CREATE_EMP in anonymous block. This has worked for me:
begin
CREATE_EMP(58, 'John', 'Testy', 'Here Lane', 'Himble', 'Abc','1225', 'UK', 'Skipper', TO_DATE('2015/02/02','YYYY/MM/DD'), TO_DATE('2017/02/02','YYYY/MM/DD'));
end;
This is database creation and CREATE_EMP definition :
CREATE TABLE EMPLOYEE (
EMP_ID NUMBER(8,0),
FIRST_NAME VARCHAR2(30),
SURNAME VARCHAR2(30),
ADDRESS VARCHAR2(50),
CITY VARCHAR2(30),
COUNTY_STATE VARCHAR2(30),
POSTCODE_ZIP VARCHAR2(10),
COUNTRY VARCHAR2(5),
JOB_TITLE VARCHAR2(20),
START_DATE DATE,
END_DATE DATE
);
//
create or replace PROCEDURE CREATE_EMP
(
empid IN EMPLOYEE.EMP_ID%TYPE,
firstname IN EMPLOYEE.FIRST_NAME%TYPE,
surname IN EMPLOYEE.SURNAME%TYPE,
address IN EMPLOYEE.ADDRESS%TYPE,
city IN EMPLOYEE.CITY%TYPE,
county IN EMPLOYEE.COUNTY_STATE%TYPE,
postcode IN EMPLOYEE.POSTCODE_ZIP%TYPE,
country IN EMPLOYEE.COUNTRY%TYPE,
jobtitle IN EMPLOYEE.JOB_TITLE%TYPE,
startdate IN EMPLOYEE.START_DATE%TYPE,
enddate IN EMPLOYEE.END_DATE%TYPE)
AS
BEGIN
INSERT INTO EMPLOYEE
(EMP_ID, FIRST_NAME, SURNAME, ADDRESS, CITY, COUNTY_STATE, POSTCODE_ZIP, COUNTRY, JOB_TITLE, START_DATE, END_DATE)
VALUES
(empid, firstname, surname, address, city, county, postcode, country, jobtitle, startdate, enddate);
END CREATE_EMP;
Of course, you should list all the columns after the table name within braces, before values keyword. And you must match the columns in the order you are inserting the values.
However, the number of values passed to the procedure is not the same as the number of parameters declared.
Also,
There is an issue with the following:
startdate IN EMPLOYEE.START_DATE%TYPE,
enddate IN EMPLOYEE.END_DATE%TYPE
2015/02/02,2017/02/02
So, 2015/02/02 and 2017/02/02 are not DATEs. You are supposed to pass DATEs.
To insert a DATE value, always use TO_DATE with proper format.
Pass the parameter values using TO_DATE:
EXECUTE create_emp(58, 'John', 'Testy', 'Here Lane', 'Himble', 'UK', 'Skipper',
TO_DATE('2015/02/02','YYYY/MM/DD'), TO_DATE('2017/02/02','YYYY/MM/DD'));
the number of parameters you passed to procedure does not match with the number of parameters in the difination of the procedure (11!=9) (the sequence and datatype of them is also important)
don't pass the date datatype as like as you passed, put them inside single qotous and use to_date function, i.e: use to_date('2015/02/02','YYYY/MM/DD') instead of 2015/02/02
Instructions:
Create two tables, named employees and departments. Preface the table names with your initials. Link the two tables (foreign key) by a column called dept. Make up a few column names for each table.
Employees Table:
create table bsemployees(
dept number primary key,
empName varchar2(20),
salary number
);
Departments Table:
create table bsdepartments(
dept number references bsemployees(dept),
deptName varchar2(20)
);
Write the following stored procedures:
• Insert a row into the employees table. If the department does not exist. Insert it into the departments table.
create or replace procedure sp_employees(
a_dept IN number,
a_empName IN varchar2,
a_salary IN number
)
as
vCount number;
BEGIN
sp_check_dept(a_dept,vCount);
insert into bsemployees values(a_dept, a_empName, a_salary);
if vCount = 0 then
dbms_output.put_line('**DEPT DOES NOT EXIST**');
insert into bsdepartments (dept, deptName) values(a_dept, NULL);
end if;
END;
/
create or replace procedure sp_check_dept(
a_dept IN number,
vCount OUT number
)
as
BEGIN
select count(*)
into vCount
from bsdepartments
where dept = a_dept;
end;
/
• Insert a row into the departments table.
create or replace procedure sp_departments(
a_dept IN number,
a_deptName IN varchar2
)
as
BEGIN
insert into bsdepartments values(a_dept, a_deptName);
END;
/
I've got it pretty much all down for this assignment except for the fact that when I try to insert a row into the departments table I am getting a integrity constraint - parent key not found error.
If I do execute sp_employees(5, 'John Doe', 90000); It will display ***DEPT DOES NOT EXIST*** and will go ahead and insert the data into bsemployees and insert the dept# into bsdepartments and the deptName will be left blank based on my if-then statement. Doing a select(*) shows me this.
However if I go ahead and do execute sp_departments(1, 'human resources'); to place a row into departments I get the parent key error. I understand that I am trying to insert something that has no parent key but I do not know how to fix it.
Your table design isn't quite correct - the dept primary key needs to be added as a foreign key to employee (not as the primary key), and employee should have its own primary key:
create table bsdepartments(
dept number primary key,
deptName varchar2(20)
);
create table bsemployees(
empName varchar2(20) primary key,
dept number references bsdepartments(dept),
salary number
);
You can then do the 'add if not exists' logic in the check_dept proc:
create or replace procedure sp_check_dept(
a_dept IN number
)
as
vCount number
BEGIN
select count(*)
into vCount
from bsdepartments
where dept = a_dept;
if (vCount = 0) then
dbms_output.put_line('**DEPT DOES NOT EXIST**');
insert into bsdepartments (dept, deptName) values(a_dept, NULL);
end if;
end;
Which then simplifies the employee insertion proc as it should be guaranteed of a department:
create or replace procedure sp_insertEmployee(
a_dept IN number,
a_empName IN varchar2,
a_salary IN number
)
as
BEGIN
sp_check_dept(a_dept);
insert into bsemployees values(a_dept, a_empName, a_salary);
END
Notes
Recommend that you name the procs in alignment with their purpose, e.g. insertEmployee vs just employees
As you've noted, the problem with the 'add if not exists' approach is that you do not have sufficient data to completely populate the department table, hence the null column (but this is what your lecturer asked for)
Your realation to table department is bad. It should linked as below
create table bsdepartments(
dept number primary key,
deptName varchar2(20)
);
and it should be linked to employee table
create table bsemployees(
dept number references bsdepartments(dept),
empName varchar2(20),
salary number
);
Then if you try inserting execute sp_departments(1, 'human resources'); it will execute
an then you have to insert the employee.
Here the employee is related to department not the department is related to employee.
First and foremost, this is for an assignment, so most of the really cool pre-written functions you'll want to suggest, I will not be allowed to use.
I have a couple tables that all have fields
creation_date
created_by
last_update_date
last_updated_by
I need to write a trigger that fills these in for creation or updating. The problem is, these tables have null values that are problematic to me. Example:
CREATE TABLE parts
(
pno NUMBER,
pname VARCHAR2(50) NOT NULL,
qoh NUMBER NOT NULL,
price NUMBER(5,2),
reorder_level NUMBER(2),
creation_date DATE NOT NULL,
created_by VARCHAR2(10) NOT NULL,
last_update_date DATE NOT NULL,
last_updated_by VARCHAR2(10) NOT NULL,
CONSTRAINT parts_PK PRIMARY KEY (pno))
These NOT NULL's are given to me and I'm not allowed to change them. So I'm having trouble conceptualizing this.
If my trigger adds these values before the field is created, I can't do an INSERT INTO with those fields blank because they're NOT NULL.
If my trigger adds these values after the field is created, I get compilation errors ORA-00903 and 00922. Invalid table name and invalid option.
I was thinking my trigger would look like
CREATE OR REPLACE TRIGGER pcreate
BEFORE UPDATE on parts
FOR EACH ROW
BEGIN
UPDATE
SET creation_date = SYSDATE;
SET created_by = USER;
SET last_update_date = SYSDATE;
SET last_updated_by = USER;
END;
/
CREATE OR REPLACE TRIGGER pchange
BEFORE UPDATE on parts
FOR EACH ROW
BEGIN
UPDATE
SET last_update_date = SYSDATE;
SET last_updated_by = USER;
END;
/
repeat for the other tables
I might be allowed to use UPSERT but I don't really know how that works.. Any suggestions are welcome. I'm really in this to learn so any other advice is appreciated.
EDIT:
My package that will not acknowledge the trigger is as follows. Do I need to call the trigger inside the package?
CREATE OR REPLACE PACKAGE process_orders
AS
PROCEDURE add_order (p_cno IN NUMBER, p_eno IN NUMBER, p_received IN DATE);
PROCEDURE add_order_details (p_ono IN NUMBER, p_pno IN NUMBER, p_qty IN NUMBER);
PROCEDURE ship_order (p_ono IN NUMBER, p_sdate IN DATE);
PROCEDURE delete_order (p_ono IN NUMBER);
FUNCTION total_emp_sales (f_eno IN NUMBER) RETURN NUMBER;
END process_orders;
/
CREATE OR REPLACE PACKAGE BODY process_orders
AS
PROCEDURE add_order (p_cno IN NUMBER, p_eno IN NUMBER, p_received IN DATE)
IS
ao_emsg VARCHAR2(100);
p_rec_today DATE;
BEGIN
SELECT SYSDATE INTO p_rec_today FROM dual;
IF p_received is null THEN
INSERT INTO orders (ono, cno, eno, received)
VALUES(order_number_seq.NEXTVAL,p_cno,p_eno,p_rec_today);
ELSE
INSERT INTO orders (ono, cno, eno, received)
VALUES(order_number_seq.NEXTVAL,p_cno,p_eno,p_received);
END IF;
EXCEPTION
WHEN OTHERS THEN
ao_emsg := substr(SQLERRM,1,100);
INSERT INTO orders_errors (ono,transaction_date,message)
VALUES(order_number_seq.CURRVAL,SYSDATE,ao_emsg);
END;
--Etc. Procedures
END;
/
In your trigger, you simply want to modify the :new record. Your triggers would look something like
CREATE OR REPLACE TRIGGER parts_before_insert
BEFORE INSERT on parts
FOR EACH ROW
BEGIN
:new.creation_date := SYSDATE;
:new.created_by := USER;
:new.last_update_date := SYSDATE;
:new.last_updated_by := USER;
END;
and
CREATE OR REPLACE TRIGGER parts_before_update
BEFORE UPDATE on parts
FOR EACH ROW
BEGIN
:new.last_update_date := SYSDATE;
:new.last_updated_by := USER;
END;
In your INSERT statement, you would omit these four columns and let the trigger fill in the values. For example (obviously, your primary keys would be coming from something like a sequence rather than being hard-coded)
SQL> insert into parts( pno, pname, qoh, price, reorder_level )
2 values( 1, 'Widget', 10, 100, 75 );
1 row created.
SQL> select *
2 from parts;
PNO PNAME QOH
---------- -------------------------------------------------- ----------
PRICE REORDER_LEVEL CREATION_ CREATED_BY LAST_UPDA LAST_UPDAT
---------- ------------- --------- ---------- --------- ----------
1 Widget 10
100 75 26-SEP-12 SCOTT 26-SEP-12 SCOTT
There is no need of executing UPDATE statement in triggers in your case. Just assign new values to the columns using :new.
CREATE OR REPLACE TRIGGER pchange
BEFORE UPDATE on parts
FOR EACH ROW
BEGIN
:new.last_update_date = SYSDATE;
:new.last_updated_by = USER;
END;