I wrote this query to delete one user from different tables using pl/sql.
Example: I run this query to delete one user:
user SPIKETJ, code 01234, code_id 85412974 and l_code_user SPIKETJ
declare
l_code_name table_2.cod_name%type;
l_code table_2.cod_emp%type;
l_code_id table_0.cod_id%type;
l_code_user table_03.cod_user%type;
begin
l_code_name := 'SPIKETJ';
l_code := '01234';
l_code_id := '85412974';
l_code_user := 'SPIKETJ';
DELETE table_2 WHERE cod_emp IN (l_code);
commit;
DELETE table_65 WHERE cod_emp IN (l_code);
commit;
DELETE table_41 WHERE cod_name IN (l_code_name);
commit;
DELETE table_18 WHERE cod_name IN (l_code_name);
commit;
DELETE table08 WHERE cod_user IN (l_code_name);
commit;
DELETE table_0 WHERE cod_docum IN (l_code_id);
commit;
DELETE table_17 WHERE cod_id IN (l_code_id);
commit;
DELETE table_03 WHERE cod_user IN (l_code_user);
commit;
END;
When I have to delete one user I only change/assign values for:
l_code_name, l_code, l_code_id, l_code_user.
But now, I have to delete almost 20 users!
So I wanna know if I have to run this query 20 times changing the variable values each time ?
OR
Can I write a query/block where running one time deletes the 20 users I wish to?
You can Create procedure as suggested above by Tony Andrews.
Procedure
Create or replace Procedure Delete_user
(l_code_name IN your_users.cod_name%type, -- Declare your IN parameters here
l_code IN your_users.cod_emp%type,
l_code_id IN your_users.cod_id%type,
l_code_user IN your_users.cod_user%type
)
AS
-- Declare your local variables
v_code_name your_users.cod_name%type := l_code_name;
v_code your_users.cod_emp%type := l_code;
v_code_id your_users.cod_id%type := l_code_id ;
v_code_user your_users.cod_user%type := l_code_user;
BEGIN
--- write your code(delete statements)
DELETE from your_users
WHERE cod_emp IN (v_code);
commit;
dbms_output.put_line( 'USER : ' || ' ' || v_code_user || ' is deleted.' );
---
--- similarly other delete statements
END DELETE_USER;
Output:
Procedure created.
check for errors using below command :
Show errors;
no errors
Call your Procedure for deleting users :
BEGIN
DELETE_USER('SPIKETJ',01234,85412974,'SPIKETJ');
DELETE_USER('JACKET',99999,111111,'JACKET');
--similary add other user details in order of the parameters declared in proc
END;
OUTPUT :
USER : SPIKETJ is deleted.
USER : JACKET is deleted.
Statement processed.
Read more here Procedures
For deleting users instead of calling procedure N (20) times.
Create or replace Procedure Delete_user
AS
v_code_id your_users.cod_id%type;
v_code_user your_users.cod_user%type ;
cursor C_users is select cod_id,cod_user from your_users
where 1=1; -- add condition to select users you wish to delete
BEGIN
OPEN C_users;
loop
Fetch C_users into v_code_id,v_code_user;
exit when C_users%NOTFOUND;
DELETE from your_users WHERE cod_emp IN (v_code_id); -- use your primary key
--- write delete statements for other tables
dbms_output.put_line( 'USER : ' || ' ' || v_code_user || ' is deleted.' );
End Loop;
commit;
Close C_users ;
END DELETE_USER;
-- Procedure created.
Output:
USER : mahi is deleted.
USER : xyz is deleted.
Statement processed.
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;
actually I'm creating a before insert or update or delete trigger which will look on a table IMP_CUSTOMER and log the dataset which was updated, inserted or deleted into a table LOG_IMP_CUSTOMER. Everything work's fine but I just missing one point:
The data in the table can be changed by different database user and I'm trying to get the user which has done the change on the table to log that also into my log table.
This is my trigger until now:
CREATE OR REPLACE TRIGGER TRG_LOG_IMP_CUSTOMER
BEFORE INSERT OR UPDATE OR DELETE ON IMP_CUSTOMER
REFERENCING OLD AS old_buffer NEW AS new_buffer FOR EACH ROW
DECLARE
log_date TIMESTAMP;
sql_type VARCHAR(1);
log_user VARCHAR(10);
BEGIN
-- set log_date
log_date := SYSDATE;
-- set sql_type
IF INSERTING THEN sql_type := 'I';
END IF;
IF UPDATING THEN sql_type := 'U';
END IF;
IF DELETING THEN sql_type := 'D';
END IF;
-- set log_user
log_user := 'USER'; -- hardcoded for test
-- log update and delete
IF UPDATING OR DELETING THEN
INSERT INTO LOG_IMP_CUSTOMER VALUES (:old_buffer.CIF_ID,:old_buffer.PHONE_NUMBER,:old_buffer.PHONE_AREACODE,SEQ_LOG_IMP_CUSTOMER.nextval,log_date,sql_type,log_user);
END IF;
-- log insert
IF INSERTING THEN
INSERT INTO LOG_IMP_CUSTOMER VALUES
(:new_buffer.CIF_ID,:new_buffer.PHONE_NUMBER,:new_buffer.PHONE_AREACODE,SEQ_LOG_IMP_CUSTOMER.nextval,log_date,sql_type,log_user);
END IF;
END;
/
I just searching for any way to set log_user to the user which has done the change.
Some good ideas?
Thanks and regards,
David
you can edit like below.
log_user := sys_context('USERENV','SESSION_USER');
I am trying to update salary of employees using forall. Whenever any error occurs while updating I need to save for which employee id error has occurred.
But it gives following error while compiling
Error(14,24): PLS-00201: identifier 'INDX' must be declared
Below is my code
PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
EXECUTE IMMEDIATE 'UPDATE EMPLOYEES SET SALARY=SALARY+10000 WHERE EMP_ID=:1'
USING V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR J IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
lv_error_string:=lv_error_string
||sqlerrm (-sql%bulk_exceptions(j).error_code)
|| ' for'||V_EMP_ID(INDX);
END LOOP;
END;
Use this: The error is that in exception block you are trying to access a loop variable that is being used in begin block.
So your || ' for'||V_EMP_ID(INDX); should be || ' for'||V_EMP_ID(J);
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
EXECUTE IMMEDIATE 'UPDATE EMPLOYEES SET SALARY=SALARY+10000 WHERE EMP_ID=:1'
USING V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR J IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
lv_error_string:=lv_error_string
||sqlerrm (-sql%bulk_exceptions(j).error_code)
|| ' for'||V_EMP_ID(J);
END LOOP;
END;
Not sure why you use Execute Immediate when you can easily do as below:
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
UPDATE EMPLOYEES
SET SALARY=SALARY+10000
WHERE EMP_ID= V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR J IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
lv_error_string:=lv_error_string
||sqlerrm (-sql%bulk_exceptions(j).error_code)
|| ' for'||V_EMP_ID(J);
END LOOP;
END;
I would suggest to go with a single DML statement. And yes DML error loggins is possible.Hope this helps
--Creating a error log table
BEGIN
DBMS_ERRLOG.create_error_log (dml_table_name => 'EMPLOYEES');
END;
/
--ERR$_EMPLOYEES --> Errro table created
--Insertion with erroreous record
UPDATE EMPLOYEES
SET SALARY = SALARY + 10000
where EMP_ID in (<EMP_ID COLLECTION array
OR simple EMP_IDs>) LOG ERRORS
INTO ERR$_EMPLOYEES ('UPDATE') REJECT LIMIT UNLIMITED;
--Error will be logged into ERR$_EMPLOYEES table
I want to execute an pl/sql script via terminal but I can't manage to get it to work. It first checks whether an user exists and if he does then it copies data from some table of that user.
Problem arises when there is no user - script doesn't work because it says that table or view does not exist, and that means it somehow precompiles it, while I want it to execute line by line.
Here it is:
DECLARE
v_count INTEGER := 0;
BEGIN
SELECT COUNT (1) INTO v_count FROM SYS.DBA_USERS WHERE username = UPPER ('B');
if v_count = 0 then
DBMS_OUTPUT.put_line ('Fail');
else
insert into A.some_table (some_column)
select some_column from B.some_table
where some_column = "x";
end if;
END;
/
it throws error that table does not exist at line select some_column from B.some_table because while it indeed does not exist (the user does not) the script wouldn't actually go there.
You need to use dynamic PL/SQL for the insert, so that it is not validated at compile time but only at runtime:
DECLARE
v_count INTEGER := 0;
BEGIN
SELECT COUNT (1) INTO v_count FROM SYS.DBA_USERS WHERE username = UPPER ('B');
if v_count = 0 then
DBMS_OUTPUT.put_line ('Fail');
else
EXECUTE IMMEDIATE
'insert into A.some_table (some_column)
select some_column from B.some_table
where some_column = ''x''';
end if;
END;
/
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