DDL ON SCHEMA trigger - eventtrigger

Can anyone please tell me whats going on here...
CREATE TRIGGER afr_alt_trig AFTER ALTER ON SCHEMA
cols ora_name_list_t;
BEGIN
IF (ora_dict_obj_type = 'TABLE') THEN
select column_name bulk collect into cols from user_tab_cols where table_name = ora_dict_obj_name;
FOR i IN cols.first .. cols.last LOOP
dbms_output.put_line(cols(i));
END LOOP;
END IF;
END;
The above trigger is expected to display the list of all the columns in a table after the ALTER TABLE command is executed.
It works just fine when I ALTER a table with column(s) without any constraints.
Ex: Alter Table tab_xxx ADD(nucol char);--FINE
However, if I add a new column with a constraint like
Ex: ALTER TALE tab_xxx ADD(n number NOT NULL);
then this new column is not immediately reflected in the USER_TAB_COLS DD view and the FOR loop above to display the names of all the columns DOESN'T show this NEW column added.
Thanks already.

Related

Oracle SQL only drop a column if a table exists

For Microsoft SQL Server I have following statement to only drop a column if the table exist.
IF EXISTS(SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TEST_TABLE')
ALTER TABLE TEST_TABLE DROP COLUMN LEGACY_VALUE
GO
I was wondering if there was a related IF-EXISTS mechanism is present in Oracle.
All the metadata about the columns in Oracle Database is accessible using one of the following views.
user_tab_cols; -- For all tables owned by the user
all_tab_cols ; -- For all tables accessible to the user
dba_tab_cols; -- For all tables in the Database.
So, if you are looking for a column that exists and want to drop it, your code may look something like this ( see below).
Since this appears to be a one time task, is the effort really worth it?
DECLARE
v_column_exists number := 0;
BEGIN
Select count(*) into v_column_exists
from user_tab_cols
where upper(column_name) = 'LEGACY_VALUE''
and upper(table_name) = 'TEST_TABLE';
--and owner = 'SCOTT --*might be required if you are using all/dba views
if (v_column_exists = 1) then
execute immediate 'alter table test_table drop column legacy_value';
end if;
end;
/

Execute Immediate to Add a Column and Insert Data in this New Column

I have to create a plsql block which will add a new column on a table ( with dynamic Sql) and then it will insert some data in that new added column.
When I execute my block, I got a message that says that my column is not defined, even if it has been added before the insert statement.
Do you have any idea of what could be causing this problem?
It's like my insert statement doesn't know that the new column has been added.
If you add new column and update/insert data in the new column using dynamic SQL then it will work.
Example -
begin
execute immediate 'ALTER TABLE table_name ADD column_name column-definition';
execute immediate 'update table_name set column_name =''sample-data''';
COMMIT ;
end;
But, if you add new column using dynamic SQL and use static SQL to update/insert then it will throw error message.
Reason - The static SQL is validated before its execution.
Example -
begin
execute immediate 'ALTER TABLE table_name ADD column_name column-definition';
update table_name set column_name ='sample-data';
COMMIT ;
end;

How to change Null constraint for all columns ?

I have some big tables (30+ columns) with NOT NULL constraints. I would like to change all those constraints to NULL. To do it for a single column I can use
ALTER TABLE <your table> MODIFY <column name> NULL;
Is there a way to do it for all columns in one request ? Or should I copy/paste this line for all columns (><) ?
Is there a way to do it for all columns in one request ?
Yes. By (ab)using EXECUTE IMMEDIATE in PL/SQL. Loop through all the columns by querying USER_TAB_COLUMNS view.
For example,
FOR i IN
( SELECT * FROM user_tab_columns WHERE table_name = '<TABLE_NAME>' AND NULLABLE='N'
)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE <TABLE_NAME> MODIFY i.COLUMN_NAME NULL';
END LOOP;
In my opinion, by the time you would write the PL/SQL block, you could do it much quickly by using a good text editor. In pure SQL you just need 30 queries for 30 columns.
For a single table you can issue a single alter table command to set the listed columns to allow null, which is a little more efficient than running one at a time, but you still have to list every column.
alter table ...
modify (
col1 null,
col1 null,
col3 null);
If you were applying not null constraints then this would be more worthwhile, as they require a scan of the table to ensure that no nulls are present, and (I think) an exclusive table lock.
You can query user_tab_cols and combine it with a FOR cursor & EXECUTE IMMEDIATE to modify all not null columns - the PL/SQL block for doing like that would look like so:
DECLARE
v_sql_statement VARCHAR2(2000);
BEGIN
FOR table_recs IN (SELECT table_name, column_name
FROM user_tab_cols
WHERE nullable = 'N') LOOP
v_sql_statement :=
'ALTER TABLE ' || table_recs.table_name || ' MODIFY ' || table_recs.column_name || ' NULL';
EXECUTE IMMEDIATE v_sql_statement;
END LOOP;
END;
If you want to do it for all columns in a database instead of the ones in current schema, you can replace user_tab_cols and put in dba_tab_cols; I'd just run the query in the FOR to ensure that the columns being fetched are indeed the correct ones to be modified

Drop table ignoring dependencies in PostgreSQL?

Is there any way at all to drop a table in PostgreSQL ignoring dependencies (not using CASCADE)?
I'm attempting to drop and recreate a table in order to add an IDENTITY column (as there seems to be no other way to do this in AWS Redshift), but I've got views that are dependent on the table.
I obviously don't want to have to temporarily modify every dependent view just so that I can drop and recreate the same table with an added column.
I can't find a way to do this.
I would do something like the following:
create table viewSQL
as select view_definition
from information_schema.views;
drop table [table you want to change] cascade;
do $$
declare
record record ;
lv_sql text;
begin
for record in select view_definition
from viewSQL loop
execute immediate 'record.view_definition';
end loop;
end $$

Oracle: Modify primary/foreignkeys and constrains inside a TRIGGER

we have an issue with the folowing trigger where we have to disable certain constraints to add the primary key of a table:
create or replace trigger TRG_NAMENSAENDERUNG_MA
after update of vname, nname on mitarbeiter
referencing new as new old as old
for each row
declare
initialien char(2);
benutzernr int;
benutzername_neu char(5);
benutzername_alt char(5);
begin
/*...
Code sets corect values to all variables.
...*/
/* the following is suposed to disable the two constraints*/
for i in (select fk_session_log_ben_name, SESSION_LOGGING FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.session_logging||' DISABLE CONSTRAINT '||i.fk_session_log_ben_name||'';
end loop;
for i in (select fk_geraetekto_ben_name, GERAETEKONTO FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.geraetekonto||' DISABLE CONSTRAINT '||i.fk_geraetekto_ben_name||'';
end loop;
/*Update statements which can only work without the constraints!!: */
UPDATE BENUTZERKONTO SET BENUTZERNAME = benutzername_neu WHERE BENUTZERNAME = benutzername_alt;
UPDATE SESSION_LOGGING SET BENUTZERNAME = benutzername_neu WHERE BENUTZERNAME = benutzername_alt;
UPDATE GERAETEKONTO SET BENUTZERNAME = benutzername_neu WHERE BENUTZERNAME = benutzername_alt;
/*Supposed to re-enable the constraints. */
for i in (select fk_session_log_ben_name, SESSION_LOGGING FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.session_logging||' ENABLE CONSTRAINT '||i.fk_session_log_ben_name||'';
end loop;
for i in (select fk_geraetekto_ben_name, GERAETEKONTO FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.geraetekonto||' ENABLE CONSTRAINT '||i.fk_geraetekto_ben_name||'';
end loop;
end TRG_NAMENSAENDERUNG_MA;
It throws the error that SESSION_LOGGING would be an "invalid identifier". It is typed right though and we copied the syntax from the example from the Oracale page.
What's the easiest way to achieve what we want?
Thanks in advance!
Here's the invalid identifier, these columns do not exist in USER_CONSTRAINTS. The full error message should have included the line number and given a hint at the meaning.
select fk_session_log_ben_name, SESSION_LOGGING FROM USER_CONSTRAINTS
The code should probably be this:
select constraint_name fk_session_log_ben_name, table_name SESSION_LOGGING
FROM USER_CONSTRAINTS;
My first suggestion is to redesign the schema so that it's no need to change the PK values (especially by users). PK must be surrogate. There must be serious reasons for a decision like yours. Hope you don't need such reasons :) The redesign mentioned, methinks, would be less expensive than struggling with the problem you cast. With changing PK values you'll probably face such problems again and again as the application is evolved.