auditing all tables in a schema - sql

I was wondering if there is a way (in Oracle(11g)) to audit all of the tables in a given schema. I have a lot of tables that need to be audited and don't want to have to manually audit each individual tables. Would a cursor be appropriate in this situation? Any advice would be greatly appreciated. Cheers!
Here is the simple cursor I thought might work..
cursor table_names is
SELECT owner, table_name
FROM all_tables
where owner like 'MYSCHEMA%';
begin
for x in table_names
loop
audit_all := 'audit all on table_name';
end loop;
end;

You can use dynamic SQL to generate and execute the audit statements
DECLARE
l_sql_stmt varchar2(1000);
BEGIN
FOR t IN (SELECT owner, table_name
FROM all_tables
WHERE owner like 'MYSCHEMA%')
LOOP
l_sql_stmt := 'AUDIT ALL ON ' || t.owner || '.' || t.table_name;
EXECUTE IMMEDIATE l_sql_stmt;
END LOOP;
END;

Related

oracle - concatenate in select for drop, create, grant - lost in ''''

I am new to Oracle database, got a task to write several selects, but I do not get somethow principle, how it works (or better to say does not work). Could you please help me to find a mistake and probably you have a link to some info or converter that helps such writings.
v_sql := 'SELECT ''DROP TABLE ''||object_name||'' as
select *
FROM all_objects
WHERE object_name LIKE '''%''|| v_date ||''%'''
and object_type = ''TABLE''
and owner =''||v_owner||''';
Are you trying to generate DROP statements for a specific user? Start with the below anonymous block and add to it.
--Generate DROP statements for all tables for a user.
declare
v_owner varchar2(128) := user;
begin
for objects in
(
select distinct 'DROP TABLE "'||owner||'"."'||object_name||'"' v_sql
from all_objects
where object_type = 'TABLE'
and owner = v_owner
order by v_sql
) loop
dbms_output.put_line(objects.v_sql);
end loop;
end;
/

How to create a view in a FOR loop in Oracle SQL

What I'm trying to do is create views based off a condition between two tables, and I want it to go through all tables that meet this condition.
I've been doing some research and I found that cursors would be helpful for this sort of thing, but I've been running into a "cursor out of scope" at line 15.
DECLARE
query_str VARCHAR2(32000);
CURSOR all_syn IS
SELECT SYNONYM_NAME, TABLE_NAME
FROM ALL_SYNONYMS
WHERE SYNONYM_NAME LIKE 'S!_AG!_%' ESCAPE '!';
CURSOR our_tables IS
SELECT TABLE_NAME
FROM ALL_TABLES
WHERE TABLE_NAME LIKE 'AG!_%1' ESCAPE '!';
BEGIN
query_str := 'CREATE OR REPLACE VIEW ' || LTRIM(all_syn.SYNONYM_NAME, 'S_') || 'AS
SELECT TO_CHAR(itemnum) itemnum,
TO_CHAR(keywordnum) keywordnum,
TO_CHAR(keysetnum) keysetnum,
MOD_BY_EMPLOYEE,
MOD_BY_PROCESS,
MOD_DATE_EMPLOYEE,
MOD_DATE_PROCESS
FROM all_syn.SYNONYM_NAME,
our_tables.TABLE_NAME
WHERE our_tables.TABLE_NAME = ' || LTRIM(all_syn.SYNONYM_NAME, 'S_');
FOR v_rec IN all_syn LOOP
IF (v_rec.TABLE_NAME LIKE 'KEYXITEM%') THEN
EXECUTE IMMEDIATE query_str;
END IF;
END LOOP;
END;
The reason I am doing this is because my company has tables that aren't directly connected to a certain 3rd party DB link, so they had me change the table names by putting a 1 at the end of the affected tables, creating synonyms for these tables with the DB link, and then make views of these synonyms with the original table name so that they now have the DB link and act as the original table so that we don't have to change any code. I have to join the synonym tables with the changed tables, because we added some attributes that the 3rd party tables don't have.
If anyone has any suggestions or advice, it would be greatly appreciated! I'm new to using dynamic sql and PL/SQL, so bear with me please.
EDIT:
So I've improved my code, and I feel like I'm getting closer to my desired results, however I'm getting this weird error:
line 28, column 52:
PLS-00357: Table,View Or Sequence reference 'ALL_TABLES.TABLE_NAME' not allowed in this context
Which doesn't make sense to me as I'm declaring it in the query.
BEGIN
FOR v_rec IN all_syn LOOP
IF (v_rec.TABLE_NAME LIKE 'KEYXITEM%') THEN
query_str := 'CREATE OR REPLACE VIEW ' || LTRIM(v_rec.SYNONYM_NAME, 'S_') || ' AS
SELECT itemnum AS item_num,
keywordnum AS key_word_num,
keysetnum AS key_set_num,
MOD_BY_EMPLOYEE,
MOD_BY_PROCESS,
MOD_DATE_EMPLOYEE,
MOD_DATE_PROCESS,
FROM ( SELECT TABLE_NAME
FROM ALL_TABLES
WHERE TABLE_NAME LIKE ' || '''AG!_%1''' || ' ESCAPE ' || '''!''' || '
AND ' || RTRIM(ALL_TABLES.TABLE_NAME, '1') ||' = ' || LTRIM(v_rec.SYNONYM_NAME, 'S_') || ') our_tables,
' || v_rec.SYNONYM_NAME;
-- EXECUTE IMMEDIATE query_str;
END IF;
dbms_output.put_line(query_str);
END LOOP;
END;
You cannot reference cursor like that. Move the query_str creation inside the FOR LOOP and reference the record variable.
EDIT: I've tried to fix the FROM/WHERE clause, but you might be missing a join condition there.
DECLARE
query_str VARCHAR2(32000);
CURSOR all_syn IS
SELECT SYNONYM_NAME, TABLE_NAME
FROM ALL_SYNONYMS
WHERE SYNONYM_NAME LIKE 'S!_AG!_%' ESCAPE '!';
CURSOR our_tables IS
SELECT TABLE_NAME
FROM ALL_TABLES
WHERE TABLE_NAME LIKE 'AG!_%1' ESCAPE '!';
BEGIN
FOR v_rec IN all_syn LOOP
IF (v_rec.TABLE_NAME LIKE 'KEYXITEM%') THEN
query_str := 'CREATE OR REPLACE VIEW ' || LTRIM(v_rec.SYNONYM_NAME, 'S_') || 'AS
SELECT TO_CHAR(itemnum) itemnum,
TO_CHAR(keywordnum) keywordnum,
TO_CHAR(keysetnum) keysetnum,
MOD_BY_EMPLOYEE,
MOD_BY_PROCESS,
MOD_DATE_EMPLOYEE,
MOD_DATE_PROCESS
FROM ' || v_rec.SYNONYM_NAME || ',
' || v_rec.TABLE_NAME || '
WHERE ' || v_rec.TABLE_NAME = ' || LTRIM(v_rec.SYNONYM_NAME, 'S_');
EXECUTE IMMEDIATE query_str;
END IF;
END LOOP;
END;

Alter every table of a schema that has a name like 'something'?

I'd like to know if it is possible to alter every single table in a schema that contains a column name like 'something' in Oracle DB.
You can use a loop to iterate over USER_TAB_COLUMNS and generate the SQL statement:
declare
l_SQL varchar2(4000);
begin
for cur in (
select table_name, column_name
from user_tab_columns utc
where upper(utc.column_name) like '%SOMETHING%')
loop
l_SQL := 'alter table ' || cur.table_name || ' drop column ' || cur.column_name;
dbms_output.put_line(l_SQL);
-- execute immediate l_SQL; -- UNCOMMENT TO RUN; DO NOT DO THIS IN PRODUCTION!
end loop;
end;
Yes this is possible. You have to dynamically create the DDL or DML and execute immediate out of a PL/SQL routine. With "alter" do you mean change the content of the tables columns or do you mean change the columns properties?
EDIT:
You can use Frank's Routine but for a column modify you do this.
l_SQL := 'alter table ' || cur.table_name ||
' modify (' || cur.column_name || ' varchar2(50)); ';
I agree with Frank to not blindly modify the columns, use the dbms output as a generated script.
EDIT2:
There is one more thing I realized. Table user_tab_columns gives you also columns of views. You could exclude them by joining with user_tables:
set serveroutput on
declare
l_SQL varchar2(4000);
begin
for cur in (
select utc.table_name, utc.column_name
from user_tab_columns utc
join user_tables ut on (UT.TABLE_NAME = utc.table_name)
where upper(utc.column_name) like '%SO')
loop
l_SQL := 'alter table ' || cur.table_name || ' modify (' || cur.column_name || ' varchar2(50)); ';
dbms_output.put_line(l_SQL);
-- execute immediate l_SQL; -- UNCOMMENT TO RUN; DO NOT DO THIS IN PRODUCTION!
end loop;
end;

create view and alter in all tables

I am attempting to create a logic within the procedure using cursors to create database views for all the tables and create a new column called HISTORY_DATE for all tables in the schema. I need help building the logic below.
create or replace PROCEDURE ALTER_TABLES(
RC OUT INT
,MSG OUT VARCHAR)
AS
BEGIN
DECLARE
CURSOR TBL_CUR IS
SELECT TABLE_NAME FROM USER_TABLES;
TBL_REC TBL_CUR%ROWTYPE;
SQL_STMT VARCHAR(2000);
BEGIN
OPEN TBL_CUR;
LOOP
FETCH TBL_CUR INTO TBL_REC;
EXIT WHEN TBL_CUR%NOTFOUND;
PRINT_DETAILS(TBL_REC.TABLE_NAME);
SQL_STMT:= 'ALTER TABLE '
|| TBL_REC.TABLE_NAME
|| ' ADD HISTORY_DATE DATE'
|| ' AND'
|| ' CREATE OR REPLACE VIEW all_tbl AS'
|| ' SELECT *'
|| ' FROM USER_TABLES'
;
PRINT_DETAILS(SQL_STMT);
EXECUTE IMMEDIATE SQL_STMT;
END LOOP;
CLOSE TBL_CUR;
rollback;
END;
END;
You only want to create the view once; and you cannot do two things at once as Gordon Linoff mentioned. So take the view creation outside of the loop; something like this (untested):
create or replace PROCEDURE ALTER_TABLES(RC OUT INT
,MSG OUT VARCHAR)
AS
BEGIN
DECLARE
CURSOR TBL_CUR IS
SELECT TABLE_NAME FROM USER_TABLES;
TBL_REC TBL_CUR%ROWTYPE;
SQL_STMT VARCHAR(2000);
BEGIN
SQL_STMT := 'CREATE OR REPLACE VIEW all_tbl AS'
|| ' SELECT *'
|| ' FROM USER_TABLES';
PRINT_DETAILS(SQL_STMT);
EXECUTE IMMEDIATE SQL_STMT;
OPEN TBL_CUR;
LOOP
FETCH TBL_CUR INTO TBL_REC;
EXIT WHEN TBL_CUR%NOTFOUND;
PRINT_DETAILS(TBL_REC.TABLE_NAME);
SQL_STMT:= 'ALTER TABLE '
|| TBL_REC.TABLE_NAME
|| ' ADD (HISTORY_DATE DATE)'
;
PRINT_DETAILS(SQL_STMT);
EXECUTE IMMEDIATE SQL_STMT;
END LOOP;
CLOSE TBL_CUR;
--rollback;
END;
Now, I don't see a need to create a view all_tbl as all it is, is a copy of the view USER_TABLES -- so just use USER_TABLES -- but I left it's creation there so if you need only certain columns from USER_TABLES or certain rows, you know where to place that.

Retrieving Column Names and Data types in PLSQL

I am writing a PL SQL block that retrieves all the columns and the data types of the tables in the database. I am able to get the columns , but not the datatypes. Looking for suggestions for a good approach. Any help would be appreciated. My code is as follows
ACCEPT p_1 PROMPT 'Please enter the Table Name'
DECLARE
v_table_name VARCHAR2(40) :='&p_1';
-- First cursor
CURSOR get_tables IS
SELECT DISTINCT table_name
FROM user_tables
WHERE UPPER(table_name) = UPPER(v_table_name);
--Second cursor
CURSOR get_columns IS
SELECT DISTINCT column_name
FROM user_tab_columns
WHERE table_name = v_table_name;
v_column_name VARCHAR2(100);
-- Third Cursor
CURSOR get_types IS
SELECT data_type
FROM user_tab_columns
WHERE table_name = v_table_name;
v_data_type user_tab_columns.data_type%type;
BEGIN
-- Open first cursor
OPEN get_tables;
FETCH get_tables INTO v_table_name;
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('Table = ' || v_table_name );
DBMS_OUTPUT.PUT_LINE('=========================');
CLOSE get_tables;
-- Open second cursor
OPEN get_columns;
FETCH get_columns INTO v_column_name;
WHILE get_columns%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(' ' || v_column_name);
FETCH get_columns INTO v_column_name;
END LOOP;
CLOSE get_columns;
--Open Third Cursor
OPEN get_types;
FETCH get_types into v_data_type;
WHILE get_types%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(' ' || v_data_type );
FETCH get_types into v_data_type;
END LOOP;
CLOSE get_types;
END;
My error states PLS-00371: at most one declaration for 'V_DATA_TYPE' is permitted
Not a PLSQL guru but here's my grain.
Select data_type from user_tab_columns where TABLE_NAME = 'YourTableName'
Props to Eric, check this thread and his answer.
Remember you can use DESC command to describe an Oracle Table, View, Synonym, package or Function. It will give you name, data_type and lengh.
And if this actually works for you, you should be able to get the data for all of your tables, although I'm not a huge fan of cursors, you should do fine.
Try this:
-- Open second cursor
OPEN get_columns;
LOOP
FETCH get_columns INTO v_column_name, v_data_type;
EXIT WHEN get_columns%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(' ' || v_column_name);
END LOOP;
CLOSE get_columns;
END LOOP;
But be careful on the datatype you've chosen for v_data_type variable.
Good effort, but too much code. you need a short vacation :)
SELECT table_name,
column_name,
data_type,
data_length,
nullable
FROM cols
WHERE table_name='&YOUR_TABLE'
ORDER BY column_id
Your block has way too much code. This is all you need:
begin
for r in ( select column_name, data_type
from user_tab_columns
where table_name = upper('&&p_1')
order by column_id )
loop
dbms_output.put_line(r.column_name ||' is '|| r.data_type );
end loop;
end;
I encountered a similar problem. It can be viewed here: Retrieving Table Structure with Dynamic SQL.
Of things to note, I made sure that if data_scale = 0 I indicated it was to be a Integer, and if it was >0, it was a Double.