0

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.

Deepshikha
  • 9,896
  • 2
  • 21
  • 21
user2886453
  • 5
  • 1
  • 3
  • 1
    "It doesn't seem to work" isn't a valid error message. Be specific in what problems you're having. SQL is the general language - what RDBMS (implementation) do you have? I'm not sure a column named `last_analyzed` should have the information you want (that value may be updated even if the table referenced hasn't changed). – Clockwork-Muse Feb 21 '14 at 12:17
  • I need a sql query which return all tables in a particular schema which were updated on sysdate. There is a field last_analyzed in all_tab_columns. I tried to use that. It doesnt return correct data for me. – user2886453 Feb 21 '14 at 12:20
  • `last_analyzed` tells you when stats were last gathered; that doesn't tell you if the data in the table changed on that date, or even if any DDL changes were made. So... what do you mean by 'updated'? – Alex Poole Feb 21 '14 at 12:25
  • by updated i mean, which tables had records inserted/modified/deleted etc – user2886453 Feb 21 '14 at 12:27
  • 1
    Then your query won't show you that at all. – Alex Poole Feb 21 '14 at 12:30
  • There is no single query that will do that. You'll have to write a program. – Dan Bracuk Feb 21 '14 at 12:32
  • then what should be the required query?? – user2886453 Feb 21 '14 at 12:32
  • @Alex Poole the solutions provided are not working. – user2886453 Feb 21 '14 at 12:36
  • 'not working' isn't a valid error message either. I've added an answer adapting one of those to check each table and see if it's latest update time (based on `ORA_ROWSCN`) is a given date. That seems to be what you want? – Alex Poole Feb 21 '14 at 12:58

4 Answers4

3

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);
Incognito
  • 2,964
  • 2
  • 27
  • 40
  • When dealing with timestamps, it's preferred to query them as a range (ie, `>= start_of_day` and `< start_of_next_day`). Still, something like this should be trivially small enough to not matter – Clockwork-Muse Feb 21 '14 at 12:25
  • when i try to use it for one date like 2nd jan 2014 for which it has values, it doesn't return the records – user2886453 Feb 21 '14 at 12:26
  • You could probably get by with last_analyzed >= trunc(sysdate). It would run faster without the trunc function. – Dan Bracuk Feb 21 '14 at 12:26
  • @user2886453, in this scenario, does sysdate not represent the current date and time? – Dan Bracuk Feb 21 '14 at 12:27
  • @user2886453 How are you specifying the date? It might be simply an error related to using correct format using TO_DATE function – Incognito Feb 21 '14 at 12:29
  • @user2886453 - 'for which is has values' - if you're querying the table and seeing '2014-01-02' returned, or similar, then your NLS_DATE_FORMAT isn't showing you the time part of the column value; that doesn't mean it doesn't have one. Try to query `to_char(last_analyzed, 'YYYY-MM-DD HH24:MI:SS')` to see the difference. – Alex Poole Feb 21 '14 at 12:29
1

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.

Alex Poole
  • 183,384
  • 11
  • 179
  • 318
0

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.

ibre5041
  • 4,903
  • 1
  • 20
  • 35
-1

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'
yonsk
  • 163
  • 1
  • 8