I have the following procedure,
CREATE OR REPLACE PROCEDURE Add_Shipment_Method(
shipment_method_id_p IN NUMBER,
shipment_description_p IN VARCHAR2)
AS
BEGIN
INSERT INTO shipment_method
SELECT shipment_method_id_p, shipment_description_p
FROM dual
WHERE NOT EXISTS (SELECT * FROM SHIPMENT_METHOD WHERE SHIPMENT_METHOD_ID = shipment_method_id_p AND SHIPMENT_DESCRIPTION = shipment_description_p);
COMMIT;
EXCEPTION WHEN
OTHERS THEN
ROLLBACK;
END;
/
The procedure generally allows adding a new shipment method into the table shipment_method when the row doesn't exist.
I want to modify it and show a message box when the primary key 'shipment_method_id' does exist, and allows to write the row when it doesn't exist.
Any suggestions?
You can not show MessageBoxes from a Stored Proc.
Now for checking if the INSERT has inserted any row and show message in output window.
Use
BEGIN
INSERT INTO shipment_method
SELECT shipment_method_id_p, shipment_description_p
FROM dual
WHERE NOT EXISTS (SELECT * FROM SHIPMENT_METHOD
WHERE SHIPMENT_METHOD_ID = shipment_method_id_p
AND SHIPMENT_DESCRIPTION = shipment_description_p);
IF SQL%ROWCOUNT = 0 THEN --if this is true, then no records were added.
DBMS_OUTPUT.PUT_LINE( 'Not records added'); --writes this message
COMMIT;
Note: There should not be any other statement between the INSERT statement and "IF SQL%ROWCOUNT = 0" validation. SQL%ROWCOUNT reflects most recently executed statement.
Related
I want to make a trigger that will insert a value from a connected row. For example I have a table with 3 rows as below:
I create a trigger that will work once row 3 and 4 are deleted (in this case will be deleted at the same time). And I want to record invnr and extinvnr from row 1 based on idparent=id. I cannot seem to make it work though.
CREATE OR REPLACE TRIGGER LOG_DELETEDPAYMENTS
BEFORE DELETE ON payments
FOR EACH ROW
BEGIN
IF :old.invnr IS NULL THEN
INSERT INTO TABLE_LOG_DELETEDPAYMENTS (table_name, invnr, extinvnr, invdate, transactionid, info, createdby, deleted_by, date_of_delete)
values ('payments', :old.invnr, :old.extinvnr, :old.invdate, :old:transactionid, :old.info, :old.createdby, sys_context('userenv','OS_USER'), SYSDATE);
END IF;
END;
How can I incorporate this into the trigger above?
Try it this way:
create or replace TRIGGER LOG_DELETEDPAYMENTS
BEFORE DELETE ON payments
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
Declare
my_invnr PAYMENTS.INVNR%TYPE;
my_extinvnr PAYMENTS.EXTINVNR%TYPE;
Begin
IF :old.INVNR IS NULL THEN
Select INVNR, EXTINVNR
Into my_invnr, my_extinvnr
From PAYMENTS
Where ID = :old.IDPARENT;
--
INSERT INTO TABLE_LOG_DELETEDPAYMENTS (table_name, invnr, extinvnr, invdate, transactionid, info, createdby, deleted_by, date_of_delete)
values ('payments', my_invnr, my_extinvnr, :old.invdate, :old:transactionid, :old.info, :old.createdby, sys_context('userenv','OS_USER'), SYSDATE);
END IF;
End;
END;
You should select the values of INVNR and EXTINVNR based on ID - IDPARENT relationship and store it in the variables (my_invnr and my_extinvnr).
Those variables are used in INSERT into the log statement.
Because of the Select ... Into statement that is reading the affected table - trigger would fail with table PAYMENTS is mutating error.
To avoid that (to separate transaction from the table) you should Declare the PRAGMA AUTONOMOUS_TRANSACTION.
There will be two rows inserted into LOG as the trigger runs FOR EACH (deleted) ROW.
Regards...
This assumes your are on release 12c or greater of Oracle database.
CREATE OR REPLACE PACKAGE LOG_DELETEDPAYMENTS_PKG
AS
-- need a locally defined type for use in trigger
TYPE t_payments_tbl IS TABLE OF payments%ROWTYPE INDEX BY PLS_INTEGER;
END LOG_DELETEDPAYMENTS_PKG;
CREATE OR REPLACE PACKAGE BODY LOG_DELETEDPAYMENTS_PKG
AS
BEGIN
-- could also put the trigger code here and pass the type as a parameter to a procedure
NULL;
END LOG_DELETEDPAYMENTS_PKG;
CREATE OR REPLACE TRIGGER LOG_DELETEDPAYMENTS_CT
FOR DELETE ON payments
COMPOUND TRIGGER
l_tab LOG_DELETEDPAYMENTS_PKG.t_payments_tbl;
l_count PLS_INTEGER:= 0;
BEFORE EACH ROW IS
BEGIN
-- capture the deletes in local type
l_count := l_count + 1;
l_tab(l_count).invnr := :old.invnr;
l_tab(l_count).extinvnr := :old.extinvnr;
l_tab(l_count).invdate := :old.invdate;
l_tab(l_count).transactionid := :old.transactionid;
l_tab(l_count).info := :old.info;
l_tab(l_count).createdby := :old.createdby;
l_tab(l_count).idparent := :old.idparent;
l_tab(l_count).id := :old.id;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
FOR i IN l_tab.first .. l_tab.COUNT LOOP
IF(l_tab(i).invnr IS NULL) THEN
-- if the invoice number is NULL, then get info from parent
SELECT p.invnr
,p.extinvnr
INTO l_tab(i).invnr
,l_tab(i).extinvnr
FROM TABLE(l_tab) p
WHERE p.id = l_tab(i).idparent;
END IF;
END LOOP;
-- log all deletes
FORALL i IN 1 .. l_tab.COUNT
INSERT INTO LOG_DELETEDPAYMENTS
(table_name, invnr, extinvnr, invdate, transactionid, info, createdby, deleted_by, date_of_delete)
VALUES
('payments', l_tab(i).invnr, l_tab(i).extinvnr, l_tab(i).invdate, l_tab(i).transactionid, l_tab(i).info, l_tab(i).createdby, sys_context('userenv','OS_USER'), SYSDATE);
l_tab.delete;
END AFTER STATEMENT;
END LOG_DELETEDPAYMENTS_CT;
I'm trying to insert data in a backup table with help of rowtype as below
declare
vl_bkp_rec schema.table1%ROWTYPE;
BEGIN
FOR cur_rec IN
(SELECT *
FROM schema.table1
WHERE column_1 ='3f1d6348-014e-1000-8461-700c000493e0'
AND primary_key_column NOT IN ('8dc81f6e-0156-1000-8291-700e000493e0')
)
LOOP
INSERT INTO schema.backup_table VALUES vl_bkp_rec;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
lv_err_msg := SUBSTR(SQLERRM, 1, 2999);
DBMS_OUTPUT.PUT_LINE('Handled - error while executing script. =>'|| lv_err_msg );
ROLLBACK;
END;
/
i'm getting below error
Handled - error while executing script. =>ORA-01400: cannot insert NULL into ("schema"."backup_table"."primary_key_column")
but table1 and backup_table have exactly same structure. (created backup_table as below)
CREATE TABLE schema.backup_table AS
(SELECT * FROM schema.table1 WHERE rownum <1
);
and select query used above fetches valid data. What am I doing wrong here?
You need to use your variable in the below way. Currently in your code the variable declared as table type is not getting filled: See below how to use it.
declare
vl_bkp_rec table1%ROWTYPE;
BEGIN
FOR cur_rec IN
(SELECT *
FROM table1
)
LOOP
vl_bkp_rec:=cur_rec; --Assign values of the cursor variable to your variable
INSERT INTO backup_table VALUES vl_bkp_rec;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
--lv_err_msg := SUBSTR(SQLERRM, 1, 2999); ---you need to decalre it befor using it
DBMS_OUTPUT.PUT_LINE('Handled - error while executing script. =>' );
ROLLBACK;
END;
/
I have a nested plsql where the first needs to be done:
First, in the outer block insert a value '1' in table "A"; print the success message. NO COMMIT on this one.
Then, build an inner block inserting another value '2' in table "A" and COMMIT the same; print the success message
Come back to the outer block and then rollback the value '1' which was inserted before calling the inner block (please don’t delete the record, Rollback the same); print the success message
Check if the table "A" is having 2 records, then program should exist with error.
So basically in the end the table should have just one record-the value 2
declare
count_num integer;
procedure second_commit is
pragma autonomous_transaction;
begin
insert into Table_A values(1);
dbms_output.put_line('Successfully entered 1');
begin
insert into Table_A values(2);
commit;
dbms_output.put_line('Successfully entered 2 and committed');
end second_commit;
rollback;
dbms_output.put_line('Rollback Done');
select count(*) into count_num from Table_A;
if (count_num=2) then
dbms_output.put_line('Exit with error');
else
dbms_output.put_line('Normal Exit');
end if;
end;
If I follow the above code, the table commits both records and then rollbacks to the last commit meaning it wont rollback any record
In the above code basically I need to make the inner block (where 2 is being inserted) pragma autonomous or do something due to which the insertion of value 1 before the call of inner block rollbacks and only the record with value 2 remains
You are almost there. The second_commit procedure should be autonomous and should do only the second insert and commit:
declare
count_num integer;
procedure second_insert_and_commit is pragma autonomous_transaction;
begin
insert into Table_A values(2);
commit;
dbms_output.put_line('Successfully entered 2 and committed');
end second_insert_and_commit;
begin
insert into Table_A values(1);
dbms_output.put_line('Successfully entered 1');
second_insert_and_commit;
rollback;
dbms_output.put_line('Rollback Done');
select count(*) into count_num from Table_A;
if (count_num=2) then
dbms_output.put_line('Exit with error');
else
dbms_output.put_line('Normal Exit');
end if;
end;
1) Create a procedure (PrintProc) that prints out "This is the Final Test".
2) Create a procedure (UpdateProc) that takes a 'student Id' and then updates his State to ‘New York’.
Pic student database
Pic of faculty database
For #1 is it
CREATE OR REPLACE
PROCEDURE PrintProc IS
BEGIN
DBMS_OUTPUT.PUT_LINE(’This is the Final Test’);
END;
To execute I did
begin
PrintProc;
end;
but I got an error
For #2 is it
CREATE OR REPLACE PROCEDURE UpdateProc
AS
BEGIN
Update Student
set s_state = 'New York'
where s_state = 'WI'
END;
and got this error Error at line 6: PL/SQL: ORA-00933: SQL command not properly ended
to execute it is it
Begin
UpdateProc;
end;
6) Create a procedure (PrintStudentsProc) that prints out a list of students who have been taught by Kim Cox.
CREATE OR REPLACE PROCEDURE PrintStudentsProc
AS
BEGIN
Select S.S_ID, F.F_ID
FROM Faculty F INNER JOIN STUDENT S ON F.F_ID = S.F_ID
WHERE F.F_ID = 1
END;
and I get this error Error at line 4: PLS-00428: an INTO clause is expected in this SELECT statement
Was about to make another topic about triggers but stackoverflow bugged out again and I can't post for -9 days cause I posted 6 recent(not even recent) questions.
5) Create a trigger (UpdateTrigger) that outputs a message saying "Student record is going to be updated” Before the Update Takes place on Student Table,
I did
CREATE OR REPLACE TRIGGER UpdateTriggers
BEFORE UPDATE ON StudentsInfo
BEGIN
DBMS_OUTPUT.PUT_LINE('Student record is going to be updated');
Update StudentsInfo Set StudentsUpdated = StudentsUpdated + 1;
End;
and how would I execute it?
begin
UpdateTriggers;
end;
1. Error in PrintProc
The error in following code:
begin
PrintProc;
end;
is caused by the invalid character ’ in DBMS_OUTPUT.PUT_LINE in PrintProc. Replace ’ with ', this should resolve that error.
DBMS_OUTPUT.PUT_LINE('This is the Final Test');
2. Error in UpdateProc
The error in UpdateProc is caused by missing semi-colon in update statement. Add semicolon like the following:
Update Student
set s_state = 'New York'
where s_state = 'WI';
3. Error in PrintStudentsProc
Regarding the error in PrintStudentsProc, you can't do plain select statement inside plsql block. You need to use cursor. Also, you are missing semi-colon in the following query:
Select S.S_ID, F.F_ID
FROM Faculty F INNER JOIN STUDENT S ON F.F_ID = S.F_ID
WHERE F.F_ID = 1;
Cursor for loop example:
CREATE OR REPLACE PROCEDURE PrintStudentsProc AS
BEGIN
FOR stud_rec IN (
Select S.S_ID SID, F.F_ID FID
FROM Faculty F INNER JOIN STUDENT S ON F.F_ID = S.F_ID
WHERE F.F_ID = 1)
LOOP
DBMS_OUTPUT.PUT_LINE(stud_rec.SID||', '||stud_rec.FID);
END LOOP;
END;
/
Have a look at other types of cursors here
4. Error in Trigger
For trigger, after creating the trigger you need to execute the statement which invokes the trigger. In your case it is before update, so you need to perform a update query on the table.
CREATE OR REPLACE TRIGGER update_trigger BEFORE
update ON StudentsInfo FOR EACH ROW
DECLARE
stud_updated int;
BEGIN
DBMS_OUTPUT.PUT_LINE('Student record is going to be updated');
select StudentsUpdated into stud_updated from StudentsInfo where s_id=:new.s_sid;
--increase the value
stud_updated := stud_updated+1;
Update StudentsInfo Set StudentsUpdated = :stud_updated;
DBMS_OUTPUT.PUT_LINE('Student updated count:'||stud_updated);
END;
/
The above trigger should be able to execute, whenever you perform an update on the StudentsInfo table.
Also, check this sqlfiddle
This is my oracle stored procedure. I want to delete certain id when I pass data to procedure, but when I perform this proc. I get deleted everything that my trable has.
Can someone please check this out
CREATE OR REPLACE PROCEDURE Delete(
id IN number)
AS
BEGIN
DELETE FROM Users WHERE Users.id_user= id;
END;
/
I have tried to put :
DELETE FROM Users WHERE Users.id_user == id;
Then I get compilation error.
Have you tried DELETE FROM Users WHERE id_user = id; ?
Using == is not valid SQL for an equality check.
I still don't see why are you getting all rows deleted. DELETE FROM Users WHERE Users.id_user = id should be working properly.
More information on the DELETE STATEMENT syntax.
I have the same problem. When I pass an Id that doesn't exist in the table, everything gets deleted.
If the id exists in the table, then the procedure runs as I want it to run.
PROCEDURE tests
( jobnr IN varchar2,
x IN number,
menu in varchar2 default '1')
IS
counter number := 0;
BEGIN
delete from table_test where jobnr = jobnr;
if sql%notfound or sql%rowcount=0 then
rollback;
end if;
WHILE counter < x
LOOP
insert into table_test ( cskey, telnr, seq, jobnr, menu ) values ('Test'||counter, counter, counter, jobnr, menu );
counter := counter + 1;
END LOOP;
commit;
END;
Try this: Store input into local variable and then use this variable in your query. This worked for me.
CREATE OR REPLACE PROCEDURE Delete(
id IN number)
AS
v_id Number;
BEGIN
v_id := id;
DELETE FROM Users WHERE Users.id_user= v_id;
END;
CREATE TABLE USERS(ID NUMBER);
TABLE CREATED.
CREATE OR REPLACE PROCEDURE DeleteIDS(
id IN number)
AS
BEGIN
DELETE FROM Users WHERE id= id;
END;
/
PROCEDURE CREATED.
Here, in the table users id is there and also if you specify id in the declaration of procedure then that procedure deletes all the data.
so,
CREATE OR REPLACE PROCEDURE DeleteIDS(
idS IN number)
AS
BEGIN
DELETE FROM Users WHERE id= idS;
END;
/
PROCEDURE CREATED.
Now,
INSERT INTO USERS VALUES(10);
1 ROW INSERTED.
INSERT INTO USER VALUES(20);
1 ROW INSERTED.
COMMIT;
Now, execute the procedure
SQL>EXEC DELETEIDS(10);
PL/SQL PROGRAM SUCCESSFULLY COMPLETED.
SELECT * FROM USERS;
ID
---
2