sql query to fetch all tables in a schema that was updated on sysdate [duplicate] - sql

This question already has answers here:
How to find out when an Oracle table was updated the last time
(11 answers)
Closed 9 years ago.
need to write a sql query to fetch all tables in a schema
that was updated on sysdate.
select distinct(table_name)
from All_Tab_Columns
where owner = 'DBO'
and last_analyzed = sysdate;
It doesn't seem to work properly.

You need to apply TRUNC function on last_analyzed and sysdate and then it will work
select distinct(table_name)
from All_Tab_Columns
where owner = 'DBO'
and trunc(last_analyzed) = trunc(sysdate);

As mentioned in answers to the question I linked to, you can use the ORA_ROWSCN pseudo-column to get an idea of when the table was last updated. This will example all tables in your schema and list those which were modified on the specified date, according to the ORA_ROWSCN. This may take a while to run, of course.
set serveroutput on
declare
last_update varchar2(10);
bad_scn exception;
no_scn exception;
pragma exception_init(bad_scn, -8181);
pragma exception_init(no_scn, -1405);
begin
for r in (select table_name from all_tables where owner = 'DBO') loop
begin
execute immediate 'select to_char(scn_to_timestamp(max(ora_rowscn)), '
|| '''YYYY-MM-DD'') from DBO.' || r.table_name
into last_update;
if last_update = '2014-02-21' then
dbms_output.put_line(r.table_name || ' last updated on ' || last_update);
end if;
exception
when bad_scn then
dbms_output.put_line(r.table_name || ' - bad scn');
when no_scn then
dbms_output.put_line(r.table_name || ' - no scn');
end;
end loop;
end;
/
The exception handlers are covering views (which are listed but have no SCN), and where there is an invalid SCN for some reason; you may want to ignore those rather than displaying them.
If you are only looking for today, not a specific date, then this might be faster:
declare
start_scn number;
changed_rows number;
changed_tables number := 0;
begin
start_scn := timestamp_to_scn(trunc(systimestamp));
for r in (select table_name from all_tables where owner = 'BDO'
order by table_name) loop
execute immediate 'select count(*) from ('
|| 'select ora_rowscn from BDO.' || r.table_name
|| ') where ora_rowscn >= :1 and rownum < 2'
into changed_rows
using start_scn;
if changed_rows > 0 then
dbms_output.put_line(r.table_name || ' updated');
changed_tables := changed_tables + 1;
end if;
end loop;
dbms_output.put_line(changed_tables || ' tables updated today');
end;
/
You could do the same thing for any date really but you'd need to find the earliest and latest SCN for that day (which is more complicated for the current date). Also note that this may only work within your flashback window - if you go back to far you won't be able to translate an SCN to a timestamp anyway.

There is no easy way to do that. You have to operate table by table. Then execute this query on each table:
select max(SCN_TO_TIMESTAMP(ORA_ROWSCN)) from <table_name>;
ORA_ROWSCN is Oracle virtual pseudo-column, it is stored on block level. It contains "a sequence number" of the last transaction, which modified the database block.
The function SCN_TO_TIMESTAMP converts it into human readable date datatype.

You can use DMV (works on HEAPs as well - i.e. tables with no indexes) - you can expand to join on schemas
SELECT
OBJECT_NAME(OBJECT_ID) AS TableName, last_user_update AS UpdateDateTime
FROM
sys.dm_db_index_usage_stats
WHERE
database_id = DB_ID('PUT_DB_NAME')
AND last_user_update = 'EnterDateTimeHereToFilterOn'

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;
/

Creating a table if it doesn't exist already

I'm trying to create a table if it doesn't exist already. I'm currently checking to see if it exists in DBA_TABLES first and if that query returns nothing then insert. Is there a way to just check in the same statement so I don't have to break it up into separate queries?
This is what I have currently.
BEGIN
SELECT COUNT(*)
INTO lvnTableExists
FROM DBA_TABLES
WHERE Table_Name = 'SOME_TABLE';
IF lvnTableExists = 0 THEN
EXECUTE IMMEDIATE 'CREATE TABLE SOME_TABLE AS (SELECT * FR0M OTHER_TABLE)';
END IF;
END;
This is something that I'm going for.
DECLARE
sql VARCHAR2(100000);
BEGIN
sql := 'CREATE TABLE SOME_TABLE ' ||
'AS (SELECT * FROM OTHER_TABLE) ' ||
'WHERE NOT EXISTS (SELECT NULL ' ||
'FROM DBA_OBJECTS d WHERE d.Object_Name = 'SOME_TABLE' AND ' ||
'd.Owner = 'SOME_TABLE')';
EXECUTE IMMEDIATE sql;
END;
The problem is that, you can't put a WHERE NOT EXISTS in a CREATE TABLE AS statement.
Yes, that's really a shame that Oracle doesn't have that functionality. I'm sure it will come some day. Until then, if you want to write a PL/SQL wrapper, why not do it like that:
DEClARE
table_exists_already exception;
pragma exception_init(table_exists_already, -955 );
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE SOMETABLE...';
EXCEPTION WHEN table_exists_already THEN
DBMS_OUTPUT.PUT_LINE('Table sometable already exists');
END;
/

Invalid identifier error in oracle procedure for database link

I have below procedure for which i am passing db link as a parameter and create dynamic sql statement. While executing the procedure i am getting error as ORA-00904: "DB_CONNECTION_NAME": invalid identifier. I have declared the variable but still i am getting this error.
CREATE OR REPLACE PROCEDURE "EXT_SDR_RECEIVED"(in_db_link IN VARCHAR2)
AS
last_sm_id NUMBER := 0;
last_capt_date DATE;
l_sql VARCHAR2(5000);
db_connection_name VARCHAR2(100);
BEGIN
SELECT db_link INTO db_connection_name
FROM rator_monitoring_configuration.db_connection
WHERE db_link = in_db_link;
--DELETE DATA FROM TEMP_SDR_RECEIVED
DELETE FROM temp_sdr_received WHERE create_date < SYSDATE - 7;
-- first retrieve the last id (of the newest record) which has been imported at last extraction
SELECT last_task_id INTO last_sm_id
FROM capturing WHERE db_table = 'TEMP_SDR_RECEIVED';
SELECT capturing_date INTO last_capt_date
FROM capturing WHERE db_table = 'TEMP_SDR_RECEIVED';
dbms_output.PUT_LINE('DB' || db_connection_name);
-- retrieve all new records from remote SDR_O2 table and insert it into TEMP_SDR_RECEIVED where ID is greater than LAST_SM_ID
l_sql := 'INSERT INTO TEMP_SDR_RECEIVED(ID,RATING_CODE,A_NUMBER,CREATE_DATE,VOUCHER_ATTEMPT_ID,RATOR_BRAND_ID,BRAND_ID,STATUS_DESCRIPTION,ACCOUNT_PAYMENT_ID,SUBSCRIPTION_ID,DB_LINK)
SELECT SD.ID,SD.RATING_CODE,SD.A_NUMBER,to_date(substr(SD.ID, 1, 8), ''YYYYMMDD''),VA.ID,VA.BRAND_ID,BR.BRAND_ID,VA.STATUS_DESCRIPTION,VA.ACCOUNT_PAYMENT_ID,VA.SUBSCRIPTION_ID,DB_CONNECTION_NAME
FROM SDR_O2#' || db_connection_name || ' SD
JOIN VOUCHER_ATTEMPT#' || db_connection_name || ' VA
ON SD.ID = VA.SDR_ID,
RATOR_MONITORING_CONFIGURATION.BRAND BR
WHERE VA.BRAND_ID IS NOT NULL
AND BR.RATOR_BRAND_ID = VA.BRAND_ID
AND SD.RATING_CODE=''VOUCHER''
AND VA.STATUS_DESCRIPTION = ''USSD voucher''
AND SD.ID > LAST_SM_ID';
EXECUTE IMMEDIATE l_sql;
END ext_sdr_received;
You are referencing DB_CONNECTION_NAME in the select part of your dynamic query (look after VA.SUBSCRIPTION_ID). Do any of your 3 tables have that column? I suspect not.
I suspect that you wanted to select the value in the DB_CONNECTION_NAME variable instead. To do that, change that last part of the SELECT in your dynamic query like this:
'...,VA.SUBSCRIPTION_ID, ''' || DB_CONNECTION_NAME || '''
...
You may also want to look into how execute immediate supports parameter binding, so that, where possible, you can avoid having to write this ugly string concatenation code.
Also, I notice you are mixing join notations. That's asking for trouble. Stick to ANSI JOIN syntax.

Get max(length(column)) for all columns in an Oracle table

I need to get the maximum length of data per each column in a bunch of tables. I'm okay with doing each table individually but I'm looking for a way to loop through all the columns in a table at least.
I'm currently using the below query to get max of each column-
select max(length(exampleColumnName))
from exampleSchema.exampleTableName;
I'm basically replacing the exampleColumnName with each column in a table.
I've already went through 3-4 threads but none of them were working for me either because they weren't for Oracle or they had more details that I required (and I couldn't pick the part I needed).
I'd prefer to have it in SQL than in PLSQL as I don't have any create privileges and won't be able to create any PLSQL objects.
Got the below query to work -
DECLARE
max_length INTEGER; --Declare a variable to store max length in.
v_owner VARCHAR2(255) :='exampleSchema'; -- Type the owner of the tables you are looking at
BEGIN
-- loop through column names in all_tab_columns for a given table
FOR t IN (SELECT table_name, column_name FROM all_tab_cols where owner=v_owner and table_name = 'exampleTableName') LOOP
EXECUTE IMMEDIATE
-- store maximum length of each looped column in max_length variable
'select nvl(max(length('||t.column_name||')),0) FROM '||t.table_name
INTO max_length;
IF max_length >= 0 THEN -- this isn't really necessary but just to ignore empty columns. nvl might work as well
dbms_output.put_line( t.table_name ||' '||t.column_name||' '||max_length ); --print the tableName, columnName and max length
END IF;
END LOOP;
END;
Do let me know if the comments explain it sufficiently, else I'll try to do better. Removing table_name = 'exampleTableName' might loop for all tables as well, but this is okay for me right now.
You can try this; although it uses PL/SQL it will work from within SQL-Plus. It doesn't loop. Hopefully you don't have so many columns that the SELECT query can't fit in 32,767 characters!
SET SERVEROUTPUT ON
DECLARE
v_sql VARCHAR2(32767);
v_result NUMBER;
BEGIN
SELECT 'SELECT GREATEST(' || column_list || ') FROM ' || table_name
INTO v_sql
FROM (
SELECT table_name, LISTAGG('MAX(LENGTH(' || column_name || '))', ',') WITHIN GROUP (ORDER BY NULL) AS column_list
FROM all_tab_columns
WHERE owner = 'EXAMPLE_SCHEMA'
AND table_name = 'EXAMPLE_TABLE'
GROUP BY table_name
);
EXECUTE IMMEDIATE v_sql INTO v_result;
DBMS_OUTPUT.PUT_LINE(v_result);
END;
/

How to find Number of null column in table using PL/SQL

A database has a lot of columns (more than 100). Some of these columns have null entries. How can I find out how many columns have null entries in at least one row, without manually testing each and every column?
Try:
declare
l_count integer;
begin
for col in (select table_name, column_name
from user_tab_columns where table_name='EMP')
loop
execute immediate 'select count(*) from '||col.table_name
||' where '||col.column_name
||' is not null and rownum=1'
into l_count;
if l_count = 0 then
dbms_output.put_line ('Column '||col.column_name||' contains only nulls');
end if;
end loop;
end;
Try analyzing your table (compute statistics, don't estimate) and then (immediately) do:
select column_name, num_nulls
from all_tab_columns
where table_name = 'SOME_TABLENAME'
and owner = 'SOME_OWNER';
Of course as data later changes, this will become slightly more incorrect. If you need to get more fancy and do a field population count (fieldpop), then you'll need to loop through all rows and check for nulls explicitly (and exclude any other values you deem "not populated", perhaps a default of 0 for a number field for example).
I can give you the direction in which to research:
Check "user_tab_columns" through which you can get information related to columns in a table.
E.g.
select count(*) from user_tab_columns where table_name = 'YOURTABLENAME'
This gives you the number of columns in that table.
Together with this you would need to use a cursor, i think, to check each column for null values rather than adding a null check in WHERE clause for each column.
This will give you the number of NULL column values per row of data:
declare
TYPE refc IS REF CURSOR;
col_cv refc;
l_query varchar(3999);
v_rownum number;
v_count number;
begin
l_query := 'select rownum, ';
for col in (select table_name, column_name
from user_tab_columns where table_name='EMP')
loop
l_query := l_query ||'DECODE('||col.column_name||',NULL,1,0)+';
end loop;
l_query := l_query||'+0 as no_of_null_values from EMP';
DBMS_OUTPUT.PUT_LINE(l_query);
OPEN col_cv FOR l_query;
LOOP
FETCH col_cv into v_rownum, v_count;
EXIT WHEN col_cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_rownum || ' ' || v_count);
END LOOP;
CLOSE col_cv;
end;
I feel dirty even writing it! (It won't work when the number of columns in the table is very large and l_query overflows).
You just need to change the table name (EMP above).