I have a list of users that I need to drop from a schema. I created the table OWNERS_TO_REMOVE that has the names of the users that need to be dropped. I tried created the following cursor to drop the users, but it didn't work. Does it need a minor adjustment or do I need to drop the users in a completely different way?
DECLARE
CURSOR c_remove_owners IS
SELECT OWNER FROM OWNERS_TO_REMOVE;
v_owner OWNERS_TO_REMOVE.OWNER%TYPE;
BEGIN
OPEN c_remove_owners;
LOOP
FETCH c_remove_owners INTO v_owner;
EXIT WHEN c_remove_owners%NOTFOUND;
DROP USER v_owner CASCADE;
END LOOP;
CLOSE c_remove_owners;
END;
/
Related
I have two tables TRIP and DRIVER. When a new set of values in inserted into TRIP (to indicate a new trip being made), the values in the column TOTALTRIPMADE (which is currently empty) in the table DRIVER will increase by one. The trigger should recognise which row to update with the select statement I've made.
This is the trigger I've made:
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE := OLD.TOTALTRIPMADE+1
WHERE (SELECT L#
FROM TRIP
INNER JOIN DRIVER
ON TRIP.L# = DRIVER.L#;)
END;
/
However I get this error:
ORA-04098: trigger 'CSCI235.UPDATETOTALTRIPMADE' is invalid and failed re-validation
What should I edit in my code so that my trigger works? Thanks!
One error you made is in trying to reference OLD.TOTALTRIPMADE in your SET clause since no alias OLD exists, and unless the table TRIP contains a TOTALTRIPMADE column then the :OLD record won't contain a TOTALTRIPMADE column either (note that since this is an insert trigger the :OLD record either won't exist or won't contain any meaningful data anyway). Another error is in your WHERE clause where you are selecting L# from TRIP joined to DRIVER, but you aren't linking it back to the DRIVER table that you are attempting to update. Instead just update DRIVER where L# is equal the :NEW value of L# from the trip table. The final error I noticed is your use of , the := assignment operator which is for PLSQL code, however you are using it within SQL so just use = without the colon:
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE = nvl(TOTALTRIPMADE,0)+1
WHERE L# = :NEW.L#;
END;
/
Your code has syntax error due to which the trigger is not compiling,I have modified the trigger and it should get compiled successfully with desired results.Please check and feedback.
Please find below the script to create table and compile the trigger,
drop table trip;
create table trip (trip_id number(10),L# varchar2(10));
drop table driver;
create table driver(driver_id number(10),TOTALTRIPMADE number(10),L# varchar2(10));
drop trigger updatetotaltripmade;
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
DECLARE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE = nvl(TOTALTRIPMADE,0) + 1
WHERE DRIVER.L# = :new.L#;
END;
/
select * from ALL_OBJECTS where object_type ='TRIGGER';
Output is below from the tests i did on https://livesql.oracle.com/apex/
There are no issues in the code.The trigger is compiled successfully and is valid.
I am trying to lock specific columns in a table, in order to prevent from a mistakely UPDATE command to modify those fields. On the contrary, some other columns should be allowed to be modified. Is there any specific SQL command for doing so?
You can use a trigger to prevent this:
CREATE TRIGGER PreventUpdateOfThisThat
BEFORE UPDATE OF ThisColumn, ThatColumn OF MyTable
BEGIN
SELECT RAISE(FAIL, "don't do that!");
END;
Here is my simple PL/SQL code for demonstration purpose.
create table cust(cname varchar(10));
set SERVEROUTPUT ON;
create or replace trigger tgr
before insert on cust
for each row
enable
begin
dbms_output.put_line('Trigger hit on insert');
end;
/
insert into cust values('John');
OUTPUT:/
Table CUST created
Trigger TGR compiled
1 row inserted // *EXPECTING* Trigger hit on insert
You can't use DBMS_OUTPUT.PUT_LINE because when you insert data to your table, there is no prompt or screen which shows the execution of trigger. this applied same for procedures , functions , triggers.
Don't use commit inside a table. it will throw an exception. if you want to use commit then make the trigger pragma autonomous_transaction (i suggest not to use commit.it will automatically commit) .
Also make sure you don't modify the same table in the trigger. it will also throw and exception for mutating the data.
sample code
create table cust(cname varchar(10));
create table log(log varchar(10));
create or replace trigger tgr
before insert on cust
for each row
enable
begin
insert into log values('test');
end;
/
Don't use DBMS_OUTPUT.PUT_LINE inside a trigger to check if it was fired or not. Some of the IDEs like SQL developer might not output the message , even if you use SET SERVEROUTPUT ON.
However it could work on sqlplus . When i tried, it did display the message in sqlplus. So, it is not an issue with the database or your trigger.
SQL> insert into cust values('John');
Trigger hit on insert
And if you issue commit or rollback on the transaction, the messages might appear in sql developer.
I would suggest , it is better if you can create a log table and try to insert records into it rather than use dbms_output.
begin
INSERT INTO LOG_TABLE ( log_date,log_message) VALUES (SYSDATE,'Trigger hit on insert');
end;
/
I am testing the trigger named, "tulockout" listed below, with this alter statement..."alter user testuser account lock;" to see if the trigger log a record of what happened in table, "log_table_changes".
However, certain values are not accurately logging into the table, "log_table_changes". To be specific v_dusr.start_dt is returning NULL when the trigger, "tulockout" fires off after I execute "alter user testuser account lock;" statement.
I am not certain as to why. Can you please assist?
How can I fix this issue? Thanks.
create or replace trigger tulockout
after alter on schema
declare
cursor v_abc is
select du.username, max(us.start_dt)
from dba_users du, user_session us, users_info ui
where ui.db_user_name = du.username
and ui.db_user_name = us.user_name
and ui.db_user_name = ora_login_user;
v_dusr v_abc%ROWTYPE;
begin
if(ora_sysevent = 'ALTER' and v_dusr.username = ora_dict_obj_name and
v_dusr.account_status = 'LOCKED') then
insert into log_table_changes(username,
lastlogin_date,
notes,
execute_date,
script_name
)
values(
v_dusr.username,
v_dusr.start_dt,
ora_dict_obj_type||', '||
ora_dict_obj_name||' has been locked out.',
sysdate,
ora_sysevent
);
end;
You are declaring a cursor, and a record based on that; but you don't ever execute the cursor query or populate the variable.
Your cursor query is currently missing a group-by clause so will error when run, because of the aggregate function. You don't really need to include the user name in the select list though, as you already know that value. You are, though, later referring to the v_duser.account_status field, which doesn't exist in your cursor query/rowtype, so you need to add (and group by) that too.
The trigger also needs to be at database, not schema, level; and unless you intend to record who performed the alter command, you don't ned to refer to ora_login_user - looking that user's status up doesn't seem very helpful.
You don't really need a cursor at all; a select-into would do, something like (assuming there will always be a row returned from the joins to your user_session and users_info tables; which implies they store the username in the same case as dba_users does - although I'm not sure why you are joining to users_info at all?):
create or replace trigger tulockout
after alter on database
declare
v_start_dt user_session.start_dt%TYPE;
v_account_status dba_users.account_status%TYPE;
begin
select du.account_status, max(us.start_dt)
into v_account_status, v_start_dt
from dba_users du
join user_session us on us.db_user_name = du.username
-- join not needed?
-- join users_info ui on ui.db_user_name = us.user_name
where du.username = ora_dict_obj_name
group by du.account_status;
if(ora_sysevent = 'ALTER' and ora_dict_obj_type = 'USER'
and v_account_status = 'LOCKED') then
insert ...
and then use those date and status variables and ora_dict_obj_name(the user that was altered) in the insert.
I've also switched to modern join syntax, and tweaked the conditions a bit.
Untested, but should give you the idea.
You could make it even easier by doing a single insert ... select against those tables, removing the need for local variables.
Oracle 11g/XE
Toad 12.7.1.11
I have a newly-installed db. Connected as SYS, created a user called 'jasons' with password and granted DBA. Disconnected and reconnected as 'jasons'. Then ran the following script:
CREATE SEQUENCE people_seq
MINVALUE 0
MAXVALUE 10000
START WITH 0
INCREMENT BY 1
CACHE 20;
commit;
create table people (PID number(10), FirstName varchar(20), LastName varchar(20));
commit;
alter table people add (constraint people_pk primary key (PID));
commit;
CREATE OR REPLACE TRIGGER people_trig
BEFORE INSERT ON people
FOR EACH ROW
BEGIN
SELECT people_seq.NEXTVAL
INTO :new.pid
FROM dual;
END;
commit;
When I run the script, everything goes well until the CREATE TRIGGER section. It throws:
ORA-04089: cannot create triggers on objects owned by SYS
I just created that very table as jasons! Can somebody please tell me what's going on?
Duh...
When making a new connection in Toad there's a nice little dropdown box in the middle of the right-hand side that says "Connect As" with your choice of Normal, SYSDBA, and SYSOPER.
It defaults to SYSDBA -- but when you select 'Normal'... Well... The above script works just fine ;-)