2014-07-08 75 views
0

我正在使用Oracle數據庫,並試圖查找在某個日期更新的所有表格。所有跟蹤更新的表都有一個名爲DT_UPDATE的列。我一直想這樣的:查找在特定日期更新的所有表格

SELECT * FROM 
(SELECT TABLE_NAME FROM ALL_TAB_COLUMNS WHERE COLUMN_NAME = 'DT_UPDATE') 
WHERE DT_UPDATE = <date> 

但得到這個錯誤:

ORA-00904: "DT_UPDATE": invalid identifier 
00904. 00000 - "%s: invalid identifier" 
*Cause:  
*Action: 
Error at Line: 3 Column: 7 

我也試着走樣嵌套SELECT子句。

+0

你需要使用動態SQL,你有沒有試過? – zaratustra

+0

當我運行SELECT TABLE_NAME FROM ALL_TAB_COLUMNS WHERE COLUMN_NAME ='DT_UPDATE'時,我得到一個名爲DT_UPDATE的列的所有表的列表。然後,我想查詢所有這些表以找到DT_UPDATE中具有特定值的那些表。 – 9erNumber16

+0

@zartustra,我從來沒有嘗試過動態SQL,但它看起來很有趣。 – 9erNumber16

回答

2

正如@zaratustra所說,你必須使用動態SQL。你可以做這樣的事情:

set serveroutput on 
declare 
    counter number; 
begin 
    for r in (
    select owner, table_name 
    from all_tab_columns 
    where column_name = 'DT_UPDATE' 
) loop 
    execute immediate 'select count(*) from "' 
     || r.owner || '"."' || r.table_name 
     || '" where dt_update = :dt and rownum = 1' 
    into counter 
    using date '2014-07-07'; 

    if counter = 1 then 
     dbms_output.put_line(r.table_name); 
    end if; 
    end loop; 
end; 
/

對於每個table_name(和owner,爲了完整)在all_tab_columns鑑定爲具有所謂的dt_update列,一個新的動態選擇中產生,形式爲:

select count(*) from "<owner>"."<table_name>" 
where dt_update = date '2014-07-07' 
and rownum = 1; 

rownum = 1過濾器讓查詢執行一旦找到匹配的行就停止;因爲你說你想知道哪些表已被更新,而不是確定哪些行或確切地哪些行,如果一行匹配,那麼這就是你真正需要知道的。因此,對於每個表的動態查詢得到0或1

對於有至少一排匹配日期的表,這printd使用dbms_output表名,所以你必須有一個啓用 - 與set serveroutput on,或使用SQL Developer中的DBMS_OUTPUT面板或您最喜愛的客戶端的等效項。

如果我創建與該列一些表,但只有一個填充帶有日期我在尋找:

create table tab1 (dt_update date); 
create table tab2 (dt_update date); 
create table tab3 (dt_update date); 

insert into tab1 values (trunc(sysdate) - 1); 
insert into tab2 values (trunc(sysdate)); 

...然後運行我的匿名塊生產:

anonymous block completed 
TAB1 

明顯地使用你自己的目標日期。這假定你的日期字段不包含時間分量。如果確實如此,那麼你需要把它變成一個覆蓋整個一天的範圍。

你也可以把它變成一個流水線函數,它將日期作爲參數;這也處理日期字段與時間元素:

create or replace function get_updated_tables(p_date date) 
return sys.odcivarchar2list pipelined as 
    counter number; 
begin 
    for r in (
    select owner, table_name 
    from all_tab_columns 
    where column_name = 'DT_UPDATE' 
) loop 
    execute immediate 'select count(*) from "' 
     || r.owner || '"."' || r.table_name 
     || '" where dt_update >= :dt1 and dt_update < :dt2' 
     || ' and rownum = 1' 
    into counter 
    using p_date, p_date + interval '1' day; 

    if counter = 1 then 
     pipe row (r.table_name); 
    end if; 
    end loop; 
end; 
/

然後你可以查詢它:

select column_value from table(get_updated_tables(date '2014-07-07')); 

COLUMN_VALUE     
------------------------------ 
TAB1       

動態SQL有趣的是,當你在一個評論說,但應該只用於必要時。生成的語句在執行之前無法分析,因此在運行時可能不會識別語法或其他錯誤。另外請確保您使用綁定變量作爲值(但不包括對象名稱)以避免SQL注入。

+0

這給了我「錯誤報告 - ORA-01861:文字不匹配格式字符串 ORA-06512:在第9行 01861. 00000 - ‘文字不匹配格式字符串’ *原因:在輸入文字必須是如果 「FX」修飾符已打開,則文字必須完全匹配, 沒有額外的空格 *操作:更正格式字符串的格式字符串(除前導空格)之外的文字長度相同 *字符串以匹配文字。「它還會在錯誤報告後列出2個表格,所以它可能只是表格設置的一個問題。 – 9erNumber16

+0

@ 9erNumber16 - 'dt_update'是所有表中的'DATE'列,而不是'VARCHAR2'? –

+0

正確。我得到與zaratustra的答案相同的結果。我無法注意到列出的兩個表和可能拋出錯誤的其他表之間的任何不同之處。 – 9erNumber16

2

假設我們有一個領域dt_update三個表,和他們每個人都有一個記錄(如果更無所謂):

create table tt1 (
    dt_update date 
); 
insert into tt1 values (sysdate); 
create table tt2 (
    dt_update date 
); 
insert into tt2 values (sysdate - 1); 
create table tt3 (
    dt_update date 
); 
insert into tt3 values (sysdate - 2); 

這PL/SQL化名塊只打印表的名字是與列的值記錄dt_update大於或等於今天:

declare 
    type table_names_tp is table of user_tables.table_name%type index by binary_integer; 
    table_names table_names_tp; 
    l_res number(1); 
    l_deadline date := to_date('2014-07-08', 'YYYY-MM-DD'); 
begin 
    select table_name 
    BULK COLLECT INTO table_names 
    from user_tab_columns 
    where lower(column_name) = 'dt_update' 
    ; 
    for i in table_names.first..table_names.last 
    loop 
    execute immediate 'select count(*) from dual where exists (select null from ' || table_names(i) || ' where dt_update >= :dead_line)' 
     into l_res 
     using l_deadline; 
    if l_res = 1 
    then 
     DBMS_OUTPUT.put_line('Table ' || table_names(i) || ' was updated after ' || l_deadline); 
    end if; 
    end loop; 
end; 

您可以使用此代碼作爲一個例子來開始編寫代碼。
仔細注意保護自己免受SQL注入,不要(!)使用您的值的連接,而是始終使用綁定變量。它還可以幫助您將緩存的查詢計劃存儲在SGA中,應用程序將從SGA區域讀取數據並執行軟解析。

+0

謝謝,這工作得很好!對不起,我沒有足夠的代表投票。 – 9erNumber16

相關問題