PL SQL Loop Table after insert and update - sql

I'm trying loop through a table called broker after an insert to a different table called appointment and update a value on the broker table this what i have. When i try to create the trigger it comes up with an error saying "Trigger created with compilation errors"
CREATE OR REPLACE TRIGGER broker_level_trigger
AFTER INSERT ON appointment
DECLARE
counter integer := 1;
BEGIN
for o in (SELECT * FROM broker)
loop
SELECT COUNT(appointment.broker_id) INTO app_number FROM appointment INNER JOIN broker ON broker.broker_id = appointment.broker_id WHERE broker.broker_id = counter;
IF app_number > 15 THEN
UPDATE broker SET broker_level = 'gold' WHERE broker_id = counter;
counter := counter + 1;
end loop;
end;
/
The broker table has a field called broker_level and it changes based on the appointments, i want it to change if the broker_id field on appointments gets to more then 15

show err is a wonderful thing. (I created dummy tables you use).
SQL> CREATE OR REPLACE TRIGGER broker_level_trigger
2 AFTER INSERT ON appointment
3 DECLARE
4 counter integer := 1;
5 BEGIN
6 for o in (SELECT * FROM broker)
7 loop
8 SELECT COUNT(appointment.broker_id)
9 INTO app_number
10 FROM appointment INNER JOIN broker
11 ON broker.broker_id = appointment.broker_id
12 WHERE broker.broker_id = counter;
13
14 IF app_number > 15 THEN
15 UPDATE broker SET
16 broker_level = 'gold'
17 WHERE broker_id = counter;
18 counter := counter + 1;
19
20 end loop;
21 end;
22 /
Warning: Trigger created with compilation errors.
SQL> show err
Errors for TRIGGER BROKER_LEVEL_TRIGGER:
LINE/COL ERROR
-------- -----------------------------------------------------------------
18/7 PLS-00103: Encountered the symbol "LOOP" when expecting one of
the following:
if
If you look closer, you'll see that IF misses its END IF. Let's add it:
SQL> CREATE OR REPLACE TRIGGER broker_level_trigger
2 AFTER INSERT ON appointment
3 DECLARE
4 counter integer := 1;
5 BEGIN
6 for o in (SELECT * FROM broker)
7 loop
8 SELECT COUNT(appointment.broker_id)
9 INTO app_number
10 FROM appointment INNER JOIN broker
11 ON broker.broker_id = appointment.broker_id
12 WHERE broker.broker_id = counter;
13
14 IF app_number > 15 THEN
15 UPDATE broker SET
16 broker_level = 'gold'
17 WHERE broker_id = counter;
18 counter := counter + 1;
19 END IF; --> missing
20 end loop;
21 end;
22 /
Warning: Trigger created with compilation errors.
SQL> show err
Errors for TRIGGER BROKER_LEVEL_TRIGGER:
LINE/COL ERROR
-------- -----------------------------------------------------------------
6/5 PL/SQL: SQL Statement ignored
7/12 PLS-00201: identifier 'APP_NUMBER' must be declared
8/7 PL/SQL: ORA-00904: : invalid identifier
12/5 PL/SQL: Statement ignored
12/8 PLS-00201: identifier 'APP_NUMBER' must be declared
APP_NUMBER is missing now; you use it, but never declared it. Let's do it now:
SQL> CREATE OR REPLACE TRIGGER broker_level_trigger
2 AFTER INSERT ON appointment
3 DECLARE
4 counter integer := 1;
5 app_number number; --> missing
6 BEGIN
7 for o in (SELECT * FROM broker)
8 loop
9 SELECT COUNT(appointment.broker_id)
10 INTO app_number
11 FROM appointment INNER JOIN broker
12 ON broker.broker_id = appointment.broker_id
13 WHERE broker.broker_id = counter;
14
15 IF app_number > 15 THEN
16 UPDATE broker SET
17 broker_level = 'gold'
18 WHERE broker_id = counter;
19 counter := counter + 1;
20 END IF; --> missing
21 end loop;
22 end;
23 /
Trigger created.
SQL>
That would be it.
If you don't use SQL*Plus but some other tool, you can always query user_errors:
Warning: Trigger created with compilation errors.
SQL> select line, position, text from user_errors where name = 'BROKER_LEVEL_TRIGGER' order by sequence;
LINE POSITION TEXT
----- --------- ------------------------------------------------------------
8 12 PLS-00201: identifier 'APP_NUMBER' must be declared
9 7 PL/SQL: ORA-00904: : invalid identifier
7 5 PL/SQL: SQL Statement ignored
13 8 PLS-00201: identifier 'APP_NUMBER' must be declared
13 5 PL/SQL: Statement ignored
SQL>

Related

IF condition containing IN operator inside ORACLE Trigger is not working

I have a trigger that uses IF condition with IN operator and two variables v_audit_user and v_evdnse_user inside IN. Both variables are containing comma separated ID values. The trigger gets compiled successfully with no errors. I am not understanding why the IF condition with IN is not working. When I select the function that assigns value to the variables independently, I do see the comma separated values, so nothing is wrong with function (see screenshot).
create or replace TRIGGER TRG_CHK_HRCQA_CASE_ACTIONS
AFTER INSERT ON KDD_CASE_ACTIONS
FOR EACH ROW
DECLARE
user_audit kdd_review_owner.OWNER_ID%TYPE; /* The user that is displayed in audit */
user_evdnse kdd_review_owner.OWNER_ID%TYPE; /* The user that took action in evidence tab */
v_audit_user NUMBER; /* The HRCO/QA user from audit tab */
v_evdnse_user NUMBER; /* The HRCO/QA user from evidence tab */
LV_ERRORCODE VARCHAR2(1000);
BEGIN
/* pass the username into the variables */
SELECT kro.OWNER_ID into user_audit from kdd_review_owner kro where kro.OWNER_SEQ_ID = :NEW.ACTION_BY_ID;
SELECT kro.OWNER_ID into user_evdnse from kdd_review_owner kro where kro.OWNER_SEQ_ID = :NEW.ACTION_BY_ID;
/* fetch the comma separated IDs */
v_audit_user := F_GET_HRCQA_ACTIONS(:NEW.CASE_INTRL_ID,user_audit,'AUDIT');
v_evdnse_user := F_GET_HRCQA_ACTIONS(:NEW.CASE_INTRL_ID,user_evdnse,'EVDNSE');
-- select ENTITY_ID into v_evdnse_user from table(f_get_arg_table(F_GET_HRCQA_ACTIONS(:NEW.CASE_INTRL_ID,user_evdnse,'EVDNSE')));
/* If the action taken is by QA or HRCO role */
IF (:NEW.ACTION_SEQ_ID in (v_audit_user,v_evdnse_user))
THEN
/* then insert record in the SC_HRCQA_CASE_ACTIONS table with IS_HRCO_QA flag as Y */
Insert into SC_HRCQA_CASE_ACTIONS (ACTION_SEQ_ID,ACTION_BY_ID,ACTION_TS,STATUS_CD,CASE_INTRL_ID,ACTION_ID,NEW_CASE_OWNR_ASSGN_ID,CASE_DUE_TS,PREV_CASE_OWNR_ASSGN_ID,IS_HRCO_QA)
values (:NEW.ACTION_SEQ_ID, :NEW.ACTION_BY_ID, :NEW.ACTION_TS, :NEW.STATUS_CD, :NEW.CASE_INTRL_ID, :NEW.ACTION_ID, :NEW.NEW_CASE_OWNR_ASSGN_ID, :NEW.CASE_DUE_TS, :NEW.PREV_CASE_OWNR_ASSGN_ID,'Y');
-- ELSE
--
-- /* else the logged in user is NOT HRCO/QA hence insert record in the SC_HRCQA_CASE_ACTIONS table with IS_HRCO_QA flag as N */
--
-- Insert into SC_HRCQA_CASE_ACTIONS (ACTION_SEQ_ID,ACTION_BY_ID,ACTION_TS,STATUS_CD,CASE_INTRL_ID,ACTION_ID,NEW_CASE_OWNR_ASSGN_ID,CASE_DUE_TS,PREV_CASE_OWNR_ASSGN_ID,IS_HRCO_QA)
-- values (:NEW.ACTION_SEQ_ID, :NEW.ACTION_BY_ID, :NEW.ACTION_TS, :NEW.STATUS_CD, :NEW.CASE_INTRL_ID, :NEW.ACTION_ID, :NEW.NEW_CASE_OWNR_ASSGN_ID, :NEW.CASE_DUE_TS, :NEW.PREV_CASE_OWNR_ASSGN_ID,'N');
END IF;
EXCEPTION
WHEN OTHERS THEN LV_ERRORCODE := SQLCODE;
INSERT INTO KDD_LOGS_MSGS (LOG_DT, LOG_INFO_TX, REMARK_TX)
VALUES (SYSDATE,'ErrorCode - ' || LV_ERRORCODE,'TRG_CHK_HRCQA_CASE_ACTIONS');
END;
You cannot pass a comma-delimited string stored in a single variable to an IN condition and expect it to be parsed as multiple values as it is not.
If you want to use a single variable containing a delimited list then you will need to use string functions to find a sub-string match:
create or replace TRIGGER TRG_CHK_HRCQA_CASE_ACTIONS
AFTER INSERT ON KDD_CASE_ACTIONS
FOR EACH ROW
DECLARE
v_owner_id kdd_review_owner.OWNER_ID%TYPE;
v_audit_user VARCHAR2(1000);
v_evdnse_user VARCHAR2(1000);
LV_ERRORCODE VARCHAR2(1000);
BEGIN
SELECT OWNER_ID
into v_owner_id -- You only need one variable here
from kdd_review_owner
where OWNER_SEQ_ID = :NEW.ACTION_BY_ID;
v_audit_user := F_GET_HRCQA_ACTIONS(:NEW.CASE_INTRL_ID, v_owner_id, 'AUDIT');
v_evdnse_user := F_GET_HRCQA_ACTIONS(:NEW.CASE_INTRL_ID, v_owner_id, 'EVDNSE');
IF ','||v_audit_user||','||v_evdnse_user||',' LIKE '%,'||:NEW.ACTION_SEQ_ID||',%'
THEN
Insert into SC_HRCQA_CASE_ACTIONS (
ACTION_SEQ_ID, ACTION_BY_ID, ACTION_TS, STATUS_CD, CASE_INTRL_ID,
ACTION_ID, NEW_CASE_OWNR_ASSGN_ID, CASE_DUE_TS, PREV_CASE_OWNR_ASSGN_ID, IS_HRCO_QA
) values (
:NEW.ACTION_SEQ_ID, :NEW.ACTION_BY_ID, :NEW.ACTION_TS, :NEW.STATUS_CD, :NEW.CASE_INTRL_ID,
:NEW.ACTION_ID, :NEW.NEW_CASE_OWNR_ASSGN_ID, :NEW.CASE_DUE_TS, :NEW.PREV_CASE_OWNR_ASSGN_ID,'Y'
);
END IF;
EXCEPTION
WHEN OTHERS THEN LV_ERRORCODE := SQLCODE;
INSERT INTO KDD_LOGS_MSGS (LOG_DT, LOG_INFO_TX, REMARK_TX)
VALUES (SYSDATE,'ErrorCode - ' || LV_ERRORCODE,'TRG_CHK_HRCQA_CASE_ACTIONS');
END;
/
I don't have your tables so I'll try to illustrate it using my own code.
This is what you're doing now: to us (humans), it is obvious that L_NEW_ID (its value is 10) is contained in L_VAR1 (its value is '10,20'). However, Oracle doesn't recognize that and returns "Not OK":
SQL> declare
2 -- does L_NEW_ID exist in L_VAR1 and L_VAR2 (using your code)?
3 l_new_id number := 10;
4 --
5 l_var1 varchar2(20) := '10,20';
6 l_var2 varchar2(20) := '30,40';
7 begin
8 if l_new_id in (l_var1, l_var2) then
9 dbms_output.put_line('OK');
10 else
11 dbms_output.put_line('Not OK');
12 end if;
13 end;
14 /
Not OK
PL/SQL procedure successfully completed.
SQL>
So, what to do? One option is to split variables to rows and then check whether search value (10, right?) exists in such a list of values (rows). The result is - as you can see - "OK":
SQL> declare
2 l_new_id number := 10;
3 --
4 l_var1 varchar2(20) := '10,20';
5 l_var2 varchar2(20) := '30,40';
6 l_cnt number;
7 begin
8 -- count how many times L_NEW_ID exists in L_VAR1 nad L_VAR2
9 select count(*)
10 into l_cnt
11 from (-- split L_VAR1 into rows
12 select regexp_substr(l_var1, '[^,]+', 1, level) val
13 from dual
14 connect by level <= regexp_count(l_var1, ',') + 1
15 union all
16 -- split L_VAR2 into rows
17 select regexp_substr(l_var2, '[^,]+', 1, level)
18 from dual
19 connect by level <= regexp_count(l_var2, ',') + 1
20 ) x
21 where x.val = l_new_id;
22
23 if l_cnt > 0 then
24 dbms_output.put_line('OK');
25 else
26 dbms_output.put_line('Not OK');
27 end if;
28 end;
29 /
OK
PL/SQL procedure successfully completed.
SQL>
Just to verify it, let's change L_NEW_ID value to e.g. 99 and see what happens; as expected, "Not OK" as 99 isn't contained in 10, 20 nor 30, 40.
SQL> l2
2* l_new_id number := 10;
SQL> c/10/99
2* l_new_id number := 99;
SQL> /
Not OK
PL/SQL procedure successfully completed.
SQL>

Invalid Datatype with user defined function

I created this package and function to return a sequence of dates, given a start date and stop date (optional).
The package compiles and I can see that it is there with no errors in TOAD. Anytime I try to execute the function, I receive an error stating:
[Error] Execution (10: 8): ORA-00902: invalid datatype
I do have the right privileges as Ive created other packages with procs and functions; therefore, I'm sure its due to problems with my code.
The logic is below:
CREATE OR REPLACE PACKAGE TEST_PKG AS
TYPE table_of_dates IS TABLE OF date;
FUNCTION get_date_table(p_begin in date
,p_stop in date default sysdate
,p_next in integer default 1)
RETURN table_of_dates;
END TEST_PKG;
/
CREATE OR REPLACE package body TEST_PKG as
function get_date_table(p_begin in date
,p_stop in date default sysdate
,p_next in integer default 1)
RETURN table_of_dates
IS
date_table table_of_dates;
BEGIN
with date_sq as (
select
p_begin begin_date
,p_stop end_date from dual
)
select
d.begin_date + level - p_next
bulk collect into date_table
from date_sq d
where
1=1
/* TODO: Check this math */
connect by level <= (d.end_date - d.begin_date) + p_step
;
RETURN date_table;
END get_date_table;
end TEST_PKG;
/
Some example code to try to test the function is:
select TEST_PKG.get_date_table(sysdate) from dual; -- <--causes error shown above
If you want to use that type at SQL level (you do), then you have to create it at SQL level, not within the package.
SQL> create or replace type table_of_dates is table of date;
2 /
Type created.
Package spec:
SQL> CREATE OR REPLACE PACKAGE TEST_PKG AS
2
3
4 -- TYPE table_of_dates IS TABLE OF date;
5
6 FUNCTION get_date_table(p_begin in date
7 ,p_stop in date default sysdate
8 ,p_next in integer default 1)
9 RETURN table_of_dates;
10
11 END TEST_PKG;
12
13 /
Package created.
Package body: what is p_step at line #25? You never declared it, so I commented it.
SQL> CREATE OR REPLACE package body TEST_PKG as
2
3 function get_date_table(p_begin in date
4 ,p_stop in date default sysdate
5 ,p_next in integer default 1)
6 RETURN table_of_dates
7 IS
8
9 date_table table_of_dates;
10
11 BEGIN
12
13 with date_sq as (
14 select
15 p_begin begin_date
16 ,p_stop end_date from dual
17 )
18 select
19 d.begin_date + level - p_next
20 bulk collect into date_table
21 from date_sq d
22 where
23 1=1
24 /* TODO: Check this math */
25 connect by level <= (d.end_date - d.begin_date) -- + p_step
26 ;
27
28
29 RETURN date_table;
30 END get_date_table;
31
32 end TEST_PKG;
33 /
Package body created.
Testing:
SQL> select * From table(test_pkg.get_date_table(date '2021-07-15'));
COLUMN_VAL
----------
15.07.2021
16.07.2021
17.07.2021
18.07.2021
19.07.2021
SQL>
Seems to be OK (as far as the error you reported is concerned).

Prime Number using GOTO statement in PL/SQL

This is my code for Prime Number using goto statement
set serveroutput on;
SQL>
SQL> declare
2 msg varchar2 (30);
3 n pls_integer := 83;
4
5 begin
6 for i in 2..round( sqrt(n) ) loop
7 if n mod i=0 then
8 msg := ' is not a prime number';
9 goto when_prime;
10 end if;
11 end loop;
12
13 msg := ' is a prime number';
14
15 <>
16 dbms_output.put_line(to_char(n) || msg);
17 end;
18 /
I'm getting the following error :
<>
*
ERROR at line 15:
ORA-06550: line 15, column 1:
PLS-00103: Encountered the symbol ">" when expecting one of the following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted delimited-identifier>
<a bind variable> << continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall
merge pipe purge
ORA-06550: line 16, column 40:
PLS-00103: Encountered the symbol ";" when expecting one of the following:
. ( ) , * % & - + / at mod remainder rem <an exponent (**)>
and or || multiset
I want to check prime number or not a prime number using goto statement
You are not properly declaring the when_prime label.
Just replace this:
<>
With:
<<when_prime>>
Demo on DB Fiddle:
dbms_output:
83 is a prime number
You misused the label declaration section, it should be wrapped in << >> and not < >
Your code should be something like this:
SQL> DECLARE
2 MSG VARCHAR2(30);
3 N PLS_INTEGER := 83;
4 BEGIN
5 FOR I IN 2..ROUND(SQRT(N)) LOOP
6 IF N MOD I = 0 THEN
7 MSG := ' is not a prime number';
8 GOTO WHEN_PRIME;
9 END IF;
10 END LOOP;
11
12 MSG := ' is a prime number';
13 << WHEN_PRIME >>
14 DBMS_OUTPUT.PUT_LINE(TO_CHAR(N) || MSG);
15 END;
16 /
83 is a prime number
PL/SQL procedure successfully completed.
SQL>
UPDATE - Important
May be irrelevant for the error you are getting but you can directly use the following query to find the prime number:
SQL> WITH NUMBR AS (SELECT 83 NUMBR FROM DUAL)
2 SELECT NUMBR,
3 CASE WHEN SUM(CASE WHEN MOD(NUMBR, LEVEL) = 0
4 THEN 1 END) = 1
5 THEN 'prime'
6 ELSE 'not prime'
7 END AS "Prime?"
8 FROM NUMBR
9 CONNECT BY LEVEL <= FLOOR(NUMBR / 2)
10 GROUP BY NUMBR;
NUMBR Prime?
---------- ---------
83 prime
SQL>
Cheers!!

my trigger wont print what i want it to

so im a student working in Oracle SQL and i wrote a trigger to notify me if the item quantity is under a certain value. my trigger was created without compilation errors but when i test it i do not see the output that i want... I am sure there may be better ways to do certain parts of this but i am concerned mostly with how to get it to print to the command line. also if possible i would like the first if statement to contain a break statement so that the quantity cannot be less than 0. is that done by addint 'BREAK;' before the 'END IF;'?
SQL> #345lowqtytrigger
SQL> CREATE OR REPLACE TRIGGER low_qty_trigger
2 BEFORE INSERT OR UPDATE OF vnd_itm_qty ON Vending_Machine_Item
3 FOR EACH ROW
4 DECLARE
5 tempstr varchar2(1000);
6 name varchar2(1000);
7 vndadd varchar2(1000);
8 tempint int;
9 cursor itm_des_cursor is
10 SELECT itm_des FROM item WHERE itm_id = item.itm_id;
11 cursor vnd_addr_cursor is
12 SELECT vnd_addr FROM Vending_Machine WHERE vnd_id = Vending_Machine.vnd_id;
13 BEGIN
14 open itm_des_cursor;
15 fetch itm_des_cursor into name;
16 open vnd_addr_cursor;
17 fetch vnd_addr_cursor into vndadd;
18 IF :NEW.vnd_itm_qty < 0 THEN
19 tempstr := concat(:new.vnd_id,concat(' can not have less than 0 quantity for ',name));
20 dbms_output.put_line(tempstr);
21 end if;
22 tempint := :new.vnd_itm_qty_max*.15;
23 IF
24 :NEW.vnd_itm_qty <= tempint
25 and
26 :NEW.vnd_itm_qty >= 0
27 THEN
28 tempstr := concat('There will be less than ',
29 concat(to_char(tempint),
30 concat(' of ',
31 concat(name,
32 concat(' in Vending Machine ',
33 concat(to_char(:new.vnd_id),
34 concat(' located at ',vndadd)))))));
35 dbms_output.put_line(tempstr);
36 END IF;
37 close itm_des_cursor;
38 close vnd_addr_cursor;
39 END;
40 /
Trigger created.
SQL> SET ECHO OFF;
No errors.
SQL> spool off;
TEST CASE
SQL> update vending_machine_item set vnd_itm_qty = 1 where vnd_id = 956 and itm_id = 193;
1 row updated.
How are you testing this? It has to be in an interactive session to see any output generated by dbms_output. Try an update on vending_machine_item from a sql*plus session with set serveroutput on.

I see the error but the account is valid

SQL> CREATE or REPLACE FUNCTION custord (custNo IN number)
2 RETURN NUMBER
3 IS cust_tot NUMBER(11,2);
4 BEGIN
5 SELECT sum(cust_total_field)
6 INTO cust_tot
7 FROM ord
8 WHERE cust_number_field=custNo;
9 RETURN(cust_tot);
10 END;
11 /
Warning: Function created with compilation errors.
SQL> begin
2 dbms_output.put_line('customer 102 total is ' || custord(102));
3 end;
4 /
dbms_output.put_line('customer 102 total is ' || custord(102));
*
ERROR at line 2:
ORA-06550: line 2, column 52:
PLS-00905: object CIS605.CUSTORD is invalid
ORA-06550: line 2, column 3:
PL/SQL: Statement ignored
SQL>
I see the error but object cis605 is valid. Any ideas what I am missing?
Using the ORD table create a stored function called custord that will use a customer id (CUSTID) that will return the sum of the specified customer id TOTAL field.
When your function has been stored run the following SQL:
begin
dbms_output.put_line('customer 102 total is ' || custord(102));
end;
Your output should look like:
Results
Explain
Describe
Saved SQL
History
customer 102 total is 27775.5
Statement processed.
Try
SHOW ERRORS FUNCTION custord
Your custord function was created with compilation errors, so there is something wrong with it. This is why you're getting the object CIS605.CUSTORD is invalid error.