IF THEN ELSE NESTED PL/SQL ORACLE - oracle

I am a beginner using PL/SQL in oracle database, I just want to develop the coding that has been exist before. I want to put new condition and statement IF THEN ELSE NESTED after this code ELSIF updating THEN H_TYP := 'U';
But I am stuck with the my code, I have not yet find the way to fixing my code.
Here is my code;
create or replace TRIGGER TMCI_SUB_ITEM_MASTER_TR_R
AFTER DELETE OR INSERT OR UPDATE ON TMCI_SUB_ITEM_MASTER
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
BEGIN
DECLARE
H_ID TMCI_SUB_ITEM_MASTER_R.HST_ID%TYPE;
H_TYP TMCI_SUB_ITEM_MASTER_R.TSK%TYPE;
rdate DATE;
t_max_rev TMCI_SUB_ITEM_MASTER_R.REV%TYPE;
H_INS_USR_ID TMCI_SUB_ITEM_MASTER_R.INS_USR_ID%TYPE;
BEGIN
rdate := SYSDATE;
IF INSERTING THEN H_TYP := 'I';
...
ELSIF updating THEN H_TYP := 'U';
IF H_INS_USR_ID = 'SL01' THEN
SELECT NVL(MAX(Rev), 0) INTO t_max_rev FROM TMCI_SUB_ITEM_MASTER_R WHERE ITM_CD = :old.ITM_CD;
INSERT INTO TMCI_SUB_ITEM_MASTER_R
VALUES( H_ID,
H_TYP,
:old.ITM_CD,
CASE WHEN :old.ITM_NM <> :new.ITM_NM THEN CONCAT(:new.ITM_NM,'')
ELSE :new.ITM_NM
END);
ELSE
SELECT NVL(MAX(Rev), 0) INTO t_max_rev FROM TMCI_SUB_ITEM_MASTER_R WHERE ITM_CD = :old.ITM_CD;
INSERT INTO TMCI_SUB_ITEM_MASTER_R
VALUES( H_ID,
H_TYP,
:old.ITM_CD,
CASE WHEN :old.ITM_NM <> :new.ITM_NM THEN CONCAT(:new.ITM_NM,'*')
ELSE :new.ITM_NM
END);
END IF;
ELSIF deleting THEN H_TYP := 'D';
...
END IF;
END;
END;
If I login by SL01 result will always read in the last statement (ELSE ...). It should be execute the first statement.
I need a help for fixing this problem.

It looks like you are never setting H_INS_USR_ID to any value. I assume it is meant to the user for the incoming row? If that is the case, then
H_INS_USR_ID TMCI_SUB_ITEM_MASTER_R.INS_USR_ID%TYPE;
becomes
H_INS_USR_ID TMCI_SUB_ITEM_MASTER_R.INS_USR_ID%TYPE := :new.INS_USR_ID;

Related

inserting data select into with loop in plsql

I am just want to enter forms detail column data into a database column from a detail block and that must check first entered data which it already have in that column when i entered data data saves in other tables but in token_staus is not entering data and message me No data found for that i write a loop which is not working for me i am making some kind of mistake obviously but not sure where it is
DECLARE
TOKEN_NO NUMBER;
TOKEN_STATUS1 NUMBER;
--TOKEN_STATUS2 := :TOKEN_STATUS;
BEGIN
SELECT SR_NO, TOKEN_STATUS INTO TOKEN_NO, TOKEN_STATUS1 FROM LOOPT2 WHERE SR_NO = :TOKEN_NO;
--IF :TOKEN_STATUS IS NULL
--THEN
LOOP
GO_BLOCK('TOKEN_REC2');
FIRST_RECORD;
INSERT INTO LOOPT2(TOKEN_STATUS) VALUES(:TOKEN_STATUS);
NEXT_RECORD;
EXIT WHEN :SYSTEM.LAST_RECORD = 'TRUE';
END LOOP;
--END IF;
EXCEPTION
when others then
message (sqlerrm);
END;
Please help me
Little Foot please
If I understood you correctly, it would be something like this (check comments within the code): key thing here seems to be a BEGIN-EXCEPTION-END block within the LOOP.
DECLARE
TOKEN_NO NUMBER;
TOKEN_STATUS1 NUMBER;
BEGIN
GO_BLOCK('TOKEN_REC2');
FIRST_RECORD;
LOOP
BEGIN
SELECT SR_NO, TOKEN_STATUS
INTO TOKEN_NO, TOKEN_STATUS1
FROM LOOPT2
WHERE SR_NO = :TOKEN_NO;
-- if such a :TOKEN_NO exists, that SELECT will return some values
-- which means that you want to skip it, so - don't do anything
EXCEPTION
-- if such a :TOKEN_NO does not exist, SELECT will return
-- NO_DATA_FOUND which means that you want to perform insert
WHEN NO_DATA_FOUND THEN
INSERT INTO LOOPT2 (TOKEN_STATUS)
VALUES (:TOKEN_STATUS);
WHEN TOO_MANY_ROWS THEN
NULL;
END;
EXIT WHEN :SYSTEM.LAST_RECORD = 'TRUE';
NEXT_RECORD;
END LOOP;
END;

PL/SQL Unable to get return value of a function when called through trigger - Oracle

I am calling a function in oracle in an after update trigger. The Function is returning a value that is equated to perform a select and an insert operation.
The issue is when I am calling this function in the trigger it is getting terminated, that is it is not performing the corresponding insert operation. But the function is working fine when I execute it by itself. Also, if the trigger is run by removing the condition which is returned by the function, it is getting executed as expected.
Function:
CREATE OR REPLACE FUNCTION VERIFY_FINAL
(case_id IN number)
RETURN varchar2
IS
is_marked_final varchar2(4);
loop_count number(2);
cursor c1 is
SELECT sub_case_status from
cdm_master_sub_case
where master_id = (case_id);
BEGIN
is_marked_final := 'Y';
loop_count := 0;
FOR rec in c1
LOOP
IF (rec.sub_case_status = '1') THEN
is_marked_final := 'Y';
ELSIF (rec.sub_case_status = '2') THEN
is_marked_final := 'Y';
ELSE
loop_count := loop_count + 1;
END if;
END LOOP;
IF (loop_count > 0) THEN
is_marked_final := 'N';
END if;
RETURN is_marked_final;
END;
Trigger:
CREATE OR REPLACE TRIGGER CDM_MASTER_SUB_CASE_TRIGGER
AFTER UPDATE
on CDM_MASTER_SUB_CASE
FOR EACH ROW
DECLARE
check_var varchar2(4);
unique_id varchar2(100);
transaction_id number(10);
BEGIN
transaction_id := :new.MASTER_ID;
check_var := VERIFY_FINAL(transaction_id);
IF (check_var = 'Y') THEN
select UNIQUE_CUST_ID
INTO unique_id
from ASM355.cdm_matches
where MASTER_ID = :new.MASTER_ID
and rownum = 1;
INSERT INTO tracking_final_cases (MASTER_ID,unique_cust)
values (:new.master_id,unique_id);
END if;
END;
I would appreciate it if anyone can point me in the right direction.
1.) As tmrozek points out a return of 'N' will not do the associated insert. I might suggest having an ELSE to that IF that does something to indicate if that is what is happening.
2.) I would also point out that your SELECT INTO, if it does not find a corresponding value, would cause issues. You might want to do something to ensure that this trigger is failsafe, or have you considered what you want the code to do if that situation occurs? (Error out? Insert a null unique_id?)
3.) If you are looking at the results from a different session, bear in mind that the inserted tracking_final_cases will not be visible until you commit your changes in the session that called the trigger.
I don't know your table data but it is possible to your function to return 'N' so it wouldn't meet your trigger condition (check_var = 'Y').
If you run command like that:
update CDM_MASTER_SUB_CASE
set sub_case_status = 3;
you will probably get your problem.
Thanks guys for the time, it got resolved. I was querying a select statement in the function body over a table on which the corresponding trigger was created.

Oracle SQL Developer Triggers IF

The question is asking me to update the Reorder to either "Y" or "N" depending on whether what the store has on hand is less then the Minimum requirement.
Here is what I have so far, but it keeps giving me error. This is my first time writing triggers.
CREATE OR REPLACE TRIGGER TRG_REORDER
AFTER INSERT OR UPDATE OF ON_HAND, MINIMUM ON PART
FOR EACH ROW
BEGIN
IF NEW.ON_HAND <= NEW.MINIMUM THEN
SET NEW.REORDER = 'Y';
ELSE
SET NEW.REORDER = 'N';
END IF;
END;
Found a solution to my problems, AFTER has its limitation, so from reading this little doc about BEFORE and AFTER triggers and this other doc about triggers as well.
CREATE OR REPLACE TRIGGER TRG_REORDER
BEFORE INSERT OR UPDATE OF ON_HAND, MINIMUM ON PART
FOR EACH ROW
BEGIN
IF :NEW.ON_HAND < :NEW.MINIMUM THEN
:NEW.REORDER := 'Y';
ELSE
:NEW.REORDER := 'N';
END IF;
END;

ORA-01007 "variable not in select list" from dbms_sql.column_value call

I am trying to use dynamic SQL to sample all the data in a schema with a pattern:
DECLARE
xsql varchar2(5000);
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
varvar varchar2(500);
PROCEDURE print_rec(rec in DBMS_SQL.DESC_REC) IS
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT_LINE('col_type = '
|| rec.col_type);
DBMS_OUTPUT.PUT_LINE('col_maxlen = '
|| rec.col_max_len);
DBMS_OUTPUT.PUT_LINE('col_name = '
|| rec.col_name);
DBMS_OUTPUT.PUT_LINE('col_name_len = '
|| rec.col_name_len);
DBMS_OUTPUT.PUT_LINE('col_schema_name = '
|| rec.col_schema_name);
DBMS_OUTPUT.PUT_LINE('col_schema_name_len = '
|| rec.col_schema_name_len);
DBMS_OUTPUT.PUT_LINE('col_precision = '
|| rec.col_precision);
DBMS_OUTPUT.PUT_LINE('col_scale = '
|| rec.col_scale);
DBMS_OUTPUT.PUT('col_null_ok = ');
IF (rec.col_null_ok) THEN
DBMS_OUTPUT.PUT_LINE('true');
ELSE
DBMS_OUTPUT.PUT_LINE('false');
END IF;
END;
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
xsql:='
WITH got_r_num AS
(
SELECT e.* -- or whatever columns you want
, ROW_NUMBER () OVER (ORDER BY dbms_random.value) AS r_num
FROM dba_tab_columns e
)
SELECT * -- or list all columns except r_num
FROM got_r_num
WHERE r_num <= 10';
DBMS_SQL.PARSE(c, xsql, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
LOOP
IF DBMS_SQL.FETCH_ROWS(c)>0 THEN
NULL;
-- get column values of the row
DBMS_SQL.COLUMN_VALUE(c, 2, varvar);
--dbms_output.put_line('varvar=');
--DBMS_SQL.COLUMN_VALUE(source_cursor, 2, name_var);
--DBMS_SQL.COLUMN_VALUE(source_cursor, 3, birthdate_var);
-- Bind the row into the cursor that inserts into the destination table. You
-- could alter this example to require the use of dynamic SQL by inserting an
-- if condition before the bind.
--DBMS_SQL.BIND_VARIABLE(destination_cursor, ':id_bind', id_var);
--DBMS_SQL.BIND_VARIABLE(destination_cursor, ':name_bind', name_var);
--DBMS_SQL.BIND_VARIABLE(destination_cursor, ':birthdate_bind',
--birthdate_var);
--ignore := DBMS_SQL.EXECUTE(destination_cursor);
--ELSE
-- No more rows to copy:
--EXIT;
END IF;
END LOOP;
--EXIT WHEN d != 10;
--END LOOP;
col_num := rec_tab.first;
IF (col_num IS NOT NULL) THEN
LOOP
print_rec(rec_tab(col_num));
col_num := rec_tab.next(col_num);
EXIT WHEN (col_num IS NULL);
END LOOP;
END IF;
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
When I run that it gives me this error from the line with the dbms_sql.column_value call:
ORA-01007: variable not in select list
If I comment out that dbms_sql.column_value call it still errors but now with:
ORA-01002: fetch out of sequence
What am I doing wrong?
You have two problems in the code you posted. Firstly you have skipped part of the execution flow because you haven't called the DEFINE_COLUMN procedure. That is what is causing the ORA-01007 error, as the dynamic SQL processing hasn't been told about the select list columns via that call. For your current code you only need to define column 2, but assuming you will actually want to refer to the others you can define them in a loop. To treat them all as string for display you could do:
...
DBMS_SQL.PARSE(c, xsql, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
FOR i IN 1..col_cnt
LOOP
-- dbms_output.put_line('col_name is ' || rec_tab(i).col_name);
DBMS_SQL.DEFINE_COLUMN(c, i, varvar, 500);
END LOOP;
LOOP
IF DBMS_SQL.FETCH_ROWS(c)>0 THEN
...
If you want to do anything that needs to treat the variables as the right types you could have a local variable of each type and use the data type from the rec_tab information you already have from describe_columns to use the appropriately typed variable for each column.
The second problem, which you were hitting when you commented the column_value call, is still there once that definbe issue has been fixed. Your loop doesn't ever exit, so after you fetch the last row from the cursor you do a further invalid fetch, which throws ORA-01002. You have the code to avoid that already but it's commented out:
...
LOOP
IF DBMS_SQL.FETCH_ROWS(c)>0 THEN
-- get column values of the row
DBMS_SQL.COLUMN_VALUE(c, 2, varvar);
...
ELSE
-- No more rows to copy:
EXIT;
END IF;
END LOOP;
...
With those two changes your code runs, and dumps the view structure:
PL/SQL procedure successfully completed.
col_type = 1
col_maxlen = 30
col_name = OWNER
col_name_len = 5
col_schema_name =
col_schema_name_len = 0
col_precision = 0
col_scale = 0
col_null_ok = false
col_type = 1
col_maxlen = 30
col_name = TABLE_NAME
...
To those who find this question when accessing Oracle through ODP.NET, as I did:
We started getting this error whenever we would add column to an existing table in our application. I'm not sure what all the conditions were to make it fail, but ours were:
Run a SELECT * FROM "table".
Include a ROWNUM restriction in the WHERE clause (WHERE ROWNUM < 10).
Run that through the ODP.NET dataReader.GetSchemaTable() call.
Running unrestricted queries or running queries directly on Oracle SQL Developer did not seem to cause the error.
I've hit some pretty weird stuff in the past with Oracle connection pooling, so I eventually thought that could be the problem. The solution was to restart the web service to force all the connections to be fully dropped and recreated.
The theory is that the ODP.NET connection from the connection pool still had no idea the column existed on the table, but the column was returned by the database.

Trigger not able to initialise variable

I have trigger for auditing, which stored the action performed on any row of EMP table.
This trigger works fine, except in some cases (which occurs very rarely, and I cannot identify exact condition) it gives me
Oracle Error: ORA-01400: cannot insert NULL into ("MY_SCHEMA"."HIST_EMP"."ACTION")
CREATE OR REPLACE TRIGGER HIST_EMP_AIUD
AFTER UPDATE OR INSERT OR DELETE
ON EMP
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
v_action VARCHAR2(1) := 'D';
BEGIN
IF INSERTING THEN
v_action := 'A';
ELSIF UPDATING THEN
v_action := 'U';
END IF;
IF DELETING THEN
INSERT INTO hist_emp (source_rowid, source_date, action)
VALUES (:old.rowid, SYSDATE, v_action);
ELSIF INSERTING OR UPDATING THEN
INSERT INTO hist_emp (source_rowid, source_date, action)
VALUES (:new.rowid, SYSDATE, v_action);
END IF;
EXCEPTION
WHEN OTHERS THEN
--Code to Log
-- <some exception handling should be placed here >
END;
This generally happens when I am deleting the row, but I am not sure.
Any thought on why this will be happening? The code looks ok to me...
Something weird is going on with variable v_action initialization, I guess. Try handling all 3 possibilities:
v_action:= null;
IF INSERTING THEN
v_action := 'A';
ELSIF UPDATING THEN
v_action := 'U';
ELSIF DELETING THEN
v_action := 'D';
END IF;

Resources