How to use a bind variable in trigger body? - plsql

I'm new to PL/SQL. I'm using oracle 11g XE along with sql developer. I'm trying to create to create an after insert trigger as follows
create or replace trigger tr1
after
insert ON
employee
for each row
begin
print :new.emp_id;
end;
The employee table is as follows
create table employee
( emp_id varchar2(5) primary key,
emp_name varchar2(10),
salary number,
company varchar2(10) foreign key references companies(comp_name)
);
When I run the statement I got a 'enter binds' window for the bind variable :new. But I was confused that why do I need to enter the value for :new since it is pseudorecord. Then I entered 'employee' as the values for :new. Now I'm getting the following error.
Error(2,8): PLS-00103: Encountered the symbol "" when expecting one of the following: := . ( # % ; The symbol ":=" was substituted for "" to continue.

Your problem is not in the :new pseudorecord. The error is coming from the usage of print, which is used to print the bind variable used in successful PL/SQL block or used in an EXECUTE command. For example, you can use it this way:
VARIABLE n NUMBER
BEGIN
:n := 1;
END;
/
Then
PRINT n;
But if you want to test the value being inserted, you can use DBMS_OUTPUT.PUT_LINE like this:
create or replace trigger tr1
after
insert ON
employee
for each row
BEGIN
dbms_output.put_line(:new.emp_id);
END;
/
Enable DBMS_OUTPUT window in your SQL Developer, then run
insert into employee values(1, 'empName', 1000, 'ABC');
You'll see 1 printed out.
However, you can always test the value from the table. Because the value should be already inserted into table. You can just query.

Related

PL/SQL not functioning

Im currently trying to implement a row trigger that fires when the new Employee number inserted into the table is not continuous.
"Continuous" in a relationship to the Employee number means the first record inserted will have the Employee number 1, the second record will have the employee number 2, and each next position must have a number greater by one that a number of the previous position.
I have successfully created the trigger, however when I inserted a new record that have an Employee number that is not continuous, my trigger is not fired.
Im unsure where I went wrong and hope I can get some explanation and corrections on my code.
CREATE OR REPLACE TRIGGER CONTENUM
AFTER INSERT ON TRKEMPLOYEE
FOR EACH ROW
DECLARE
continuous_value EXCEPTION;
PRAGMA exception_init(continuous_value, -20111);
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF (:NEW.E# > :OLD.E# + 1) THEN
RAISE_APPLICATION_ERROR (-20111,'The value of Employee number must be continuous');
END IF;
END CONTENUM;
/
Here is the format of my sample TRKEMPLOYEE table
CREATE TABLE TRKEMPLOYEE(
E# NUMBER(12) NOT NULL,
NAME VARCHAR(50) NOT NULL,
DOB DATE ,
ADDRESS VARCHAR(300) NOT NULL,
HIREDATE DATE NOT NULL,
CONSTRAINT TRKEMPLOYEE_PKEY PRIMARY KEY(E#) );
Here is my insert statement.
Currently in my table TRKEMPLOYEE there is only 15 rows thus with my insert statement, the trigger should fire but it is not happening.
INSERT INTO TRKEMPLOYEE VALUES( 17, 'David', NULL, 'GB',sysdate );
Thank you.
First of all you are checking AFTER INSERT ON TRKEMPLOYEE which will be executed after the row is inserted.
Secondly, you cannot check :OLD.E# since you are not updating and you are not using a old value.
Also you should drop the trigger at all and use SEQUENCES and let Oracle take care of the auto-increment values every time you add a new employee.
If you want to continue with your current logic, fixes that can be applied:
Change AFTER INSERT ON TRKEMPLOYEE to BEFORE INSERT ON TRKEMPLOYEE
Logic should be changed as below:
CREATE OR REPLACE TRIGGER contenum BEFORE
INSERT ON trkemployee
FOR EACH ROW
DECLARE
continuous_value EXCEPTION;
PRAGMA exception_init ( continuous_value, -20111 );
PRAGMA autonomous_transaction;
max_e# INTEGER;
BEGIN
SELECT
nvl(MAX(e#), 0)
INTO max_e#
FROM
trkemployee;
IF ( :new.e# > max_e# + 1 ) THEN
raise_application_error(-20111, 'The value of Employee number must be continuous');
END IF;
END contenum;
/
I do not recommend this solution because it will start to become slower as your table starts to grow.

Stored Procedure returns "Error Code: 1054. Unknown column 'schema.table.col' in 'field list'" when Creating different temporary table on same session

When using a stored procedure to dynamically generate a table based on configuration and return a result set (SELECT) with the records in that table, the second call to that procedure to generate a different table structure returns no records and it reports a missing column from a previous temporary table of the same name.
I tried this with MariaDB 10.3 and 10.1.21 and received the same result. I have minimized my code here to the minimum to demonstrate the error after trying several variations of single and multiple sub-procedures.
I also tried using some transaction control with COMMITS after executing the process, before trying to start the process with a different parameter, but got the same results.
DROP PROCEDURE IF EXISTS CreateATable;
DELIMITER $$
CREATE PROCEDURE CreateATable( _TableType tinyint )
BEGIN
DROP TEMPORARY TABLE IF EXISTS aTable;
IF _TableType = 1 THEN
SET #SQL_Statement :=
CONCAT(
'CREATE TEMPORARY TABLE aTable (',
'the_id bigint, ',
'the_column varchar(100) ',
') engine=INNODB',
';');
ELSE
SET #SQL_Statement :=
CONCAT(
'CREATE TEMPORARY TABLE aTable (',
'the_id bigint, ',
'the_other_column varchar(100) ',
') engine=INNODB',
';');
END IF;
PREPARE stmtCreateTable FROM #SQL_Statement;
EXECUTE stmtCreateTable;
DEALLOCATE PREPARE stmtCreateTable;
SET #SQL_Statement := NULL;
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS GetATable;
DELIMITER $$
CREATE PROCEDURE GetATable()
BEGIN
CALL CreateATable( 1 );
SELECT * FROM aTable;
CALL CreateATable( 2 );
SELECT * FROM aTable;
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS GetATable2;
DELIMITER $$
CREATE PROCEDURE GetATable2(_TableType tinyint)
BEGIN
CALL CreateATable( _TableType );
SELECT * FROM aTable;
END$$
DELIMITER ;
/*
Test execution script starts here
*/
-- Just CALL Create for one and Select
CALL CreateATable( 1 );
DESCRIBE aTable;
SELECT * FROM aTable;
CALL CreateATable( 2 );
DESCRIBE aTable;
SELECT * FROM aTable;
-- -> no errors
-- now CALL procedure to Create and Select from two different temp tables
CALL GetATable();
-- -> no errors
-- now CALL procedure to CREATE AND SELECT from ONE temp table definition using a parameter to select
CALL GetATable2(1);
CALL GetATable2(2);
-- Error Code: 1054. Unknown column 'mySchema.aTable.the_column' in 'field list'
I would expect that I can pass a parameter to a stored procedure to generate a temporary table, and return the records of that temporary table. Even if I call that same procedure multiple times with different parameters on the same session.
The actual results are that when the stored procedure is called to generate the temporary table with a different table structure, it returns this error complaining about the column missing from the temporary table created in the previous invocation of that same stored procedure.
Error Code: 1054. Unknown column 'mySchema.aTable.the_column' in 'field list'
The only way I have found to prevent this error is
a. ending the jdbc connection and ending the server session
b. recompiling one of the stored procedures in the call stack
Recompiling is not viable. And ending the session seems unreasonable.
This seems like a defect. But would be interested to find if there is some way to get this to work.
This seems like a bug and you can report it directly to the MariaDB team at MariaDB bugs database.
A temporary solution is to use a prepared statement in the stored procedure GetATable2 (my test on MariaDB 10.3.16 to use EXECUTE IMMEDIATE):
...
CREATE PROCEDURE `GetATable2`(`_TableType` TINYINT)
BEGIN
CALL CreateATable(`_TableType`);
-- SELECT * FROM `aTable`;
EXECUTE IMMEDIATE 'SELECT * FROM `aTable`';
END$$
...
See dbfiddle.

Using bind variable as table name in Alter table script

FOR k in c2 LOOP
l_sql := 'ALTER TABLE :TABLE_NAME DISABLE CONSTRAINT
:CONSTRAINT_NAME CASCADE';
l_sql :='INSERT INTO TMP_CONSTRAINT (TABLE_NAME,CONSTRAINT_NAME)
VALUES ('':TABLE_NAME'', '':CONSTRAINT_NAME'')';
EXECUTE IMMEDIATE l_sql USING k.TABLE_NAME, k.CONSTRAINT_NAME;
END LOOP;
Above dynamic SQL to take the variable from a cursor and disable constraint accordingly and insert record to a temp table. I am getting error "bind variable does not exist" in the update statement.
It is actually caused by the single code in INSERT
Corrected as per following:
l_sql :='INSERT INTO TMP_ENABLED_CONSTRAINT (TABLE_NAME,CONSTRAINT_NAME) VALUES (:TABLE_NAME ,:CONSTRAINT_NAME)';

Create and insert a row into the table in stored procedure

create or replace procedure sample
as
ID VARCHAR(20);
BEGIN
execute immediate
'CREATE GLOBAL TEMPORARY TABLE UPDATE_COLUMN_NO_TP
(
NAME VARCHAR2(256)
)';
INSERT INTO UPDATE_COLUMN_NO_TP
SELECT SRC_PK_COLUMNS.PK_KEY
FROM SRC_PK_COLUMNS
WHERE NOT EXISTS (
SELECT 1
FROM TGT_PK_COLUMNS
WHERE TGT_PK_COLUMNS.ID = SRC_PK_COLUMNS.ID);
END;
Error is:
The table is no exist.
So, I want a best solution for this scenario. In my stored procedure I have 10 temporary tables. All are all dynamic creations and inserts.
Table UPDATE_COLUMN_NO_TP not exists at compile time, so you got the error.
If you created a table dynamically, you should access it dynamically.
And pay attention to Mat's comment about essence of GTT.
execute immediate '
INSERT INTO UPDATE_COLUMN_NO_TP
SELECT SRC_PK_COLUMNS.PK_KEY
FROM SRC_PK_COLUMNS
WHERE NOT EXISTS (
SELECT 1
FROM TGT_PK_COLUMNS
WHERE TGT_PK_COLUMNS.ID = SRC_PK_COLUMNS.ID
)
';

PlSQL trigger error ORA-0000 ORA-06512:

create or replace
TRIGGER "SUP" AFTER INSERT ON "EMP_REPORT" REFERENCING OLD AS "OLD" NEW AS "NEW" FOR EACH ROW
DECLARE
miclaim_supervisor_count number;
employee_company_code VARCHAR2(10);
employee_businessunit number;
projMgrs NUMBER;
supId NUMBER;
cursor projMgrsCursor is select b.BU_MEMBER_ID
from BU_MEMBER b, EMP_SUB_DIV s
where s.EMP_NO = :NEW.EMP_NO
and s.SUB_DIVISION_CODE = '01' and s.DIV_CODE = '2'
and b.BU_ID IN (select BU_ID from BU_MEMBER where BU_MEMBER_ID = :NEW.EMP_NO);
BEGIN
delete from MICL_SUPERVISORS where EMP_NO = :NEW.EMP_NO and IS_OVVERRIDDEN = 0;
select count(*) into miclaim_supervisor_count from MICL_SUPERVISORS where EMP_NO = :NEW.EMP_NO and IS_OVVERRIDDEN = 1;
select COMPANY_CODE into employee_company_code from EMPLOYEE_MASTER where EMP_NO = :NEW.EMP_NO;
projMgrs := 0;
if (employee_company_code ='F')then
OPEN projMgrsCursor;
LOOP
select micl_sup_id_seq.nextval into supId from dual;
FETCH projMgrsCursor INTO projMgrs;
EXIT WHEN projMgrsCursor%NOTFOUND;
insert into SUP VALUES ((supId), (SELECT SYSDATE FROM DUAL), :NEW.ENTRYADDEDBY_EMP_NO, 3000, 0,projMgrs, NULL,:NEW.EMP_NO);
END LOOP;
CLOSE projMgrsCursor;
else
if(miclaim_supervisor_count IS NULL or miclaim_supervisor_count<1) then
insert into SUP VALUES ((:NEW.ID), (SELECT SYSDATE FROM DUAL), :NEW.ENTRYADDEDBY_EMP_NO, 3000, 0, :NEW.SUP_EMP_NO, NULL,:NEW.EMP_NO);
end if;
end if;
END;
I created this trigger a week go but no compilation errors
But when I enter a record to EMP_REPORT it pop up an error msg saying
*INSERT INTO"EMP_REPORT" (ID, ADDEDDATE, ENTRYADDEDBY_EMP_NO, SUP_EMP_NO, EMP_NO) VALUES ('71', TO_TIMESTAMP('19-MAR-13 09.55.57.983000000 AM', 'DD-MON-RR HH.MI.SS.FF AM'), '81', '841', '5295')
ORA-00001: unique constraint (SYS_C0023329) violated
ORA-06512: at line 1
One error saving changes to table "EMP_REPORT":
Row 51: ORA-00001: unique constraint (SYS_C0023329) violated
ORA-06512: at line 1*
I cant figure out where I went wrong. pls help me :(
pls note that I cant remove constraint and its a primary key
Are you sure that the error occurs in the trigger? It looks to me like the INSERT which might be failing is the one into EMP_REPORT - possibly because there's already a row in EMP_REPORT with ID = '71'. It would be helpful if you could confirm what table SYS_C0023329 is on.
However, assuming that the message is being generated by the trigger - I only see two INSERTs in your trigger, both inserting into the SUP table, so the problem must be coming from one of these INSERTs. Either
There's already a row in SUP which has a key value (you don't show the names of the columns in your INSERT statements against SUP so I don't know what the field's name might be) greater than the current value of MICL_SUP_ID_SEQ.NEXTVAL, or
There's a row in SUP with a key value equal to the new EMP_REPORT.ID field you've supplied in the second INSERT.
This second issue, supplying a key value from one table (EMP_REPORT) as the key value for a second table (SUP) seems a bit suspicious to me, and I'd suggest looking there first. I'd think you'd want to get a value from MICL_SUP_ID_SEQ to use in the SUP table.
To verify that the issue is caused by an insert into SUP, you might try executing the following:
SELECT *
FROM ALL_CONSTRAINTS c
WHERE c.CONSTRAINT_NAME = 'SYS_C0023329';
This will tell you what table the constraint is on.
Share and enjoy.

Resources