2012-09-26 70 views
2

我是Oracle中的一名新成員。 我想創建一個包含幾個函數的包。 這是我所想要做的軟件包中的臨時表 - Oracle

function FunctionA(UserID, startdate, enddate) 
    /* Select TransactionDate, Amount 
    from TableA 
    where TransactionDate between startdate and enddate 
    and TableA.UserID = UserID */ 
    Return TransactionDate, Amount 
end FunctionA 

function FunctionB(UserID, startdate, enddate) 
    /* Select TransactionDate, Amount 
    from TableB 
    where TransactionDate between startdate and enddate 
    and TableB.UserID = UserID */ 
    Return TransactionDate, Amount 
end FunctionA 

TYPE TRANSACTION_REC IS RECORD(
      TransactionDate DATE, 
      TransactionAmt  NUMBER); 

function MainFunction(startdate, enddate) 
    return TBL 
    is 
    vTrans TRANSACTION_REC; 
begin 
    FOR rec IN 
    (Select UserID, UserName, UserStatus 
     from UserTable 
     where EntryDate between startdate and enddate) 
    LOOP 
    vTrans := FunctionA(rec.UserID, startdate, enddate) 

    if vTrans.TransactionDate is null then 
     vTrans := FunctionB(rec.UserID, startdate, enddate) 

     if vTrans.TransactionDate is null then 
      rec.UserStatus := 'Inactive' 
     endif; 
    endif; 
    END Loop; 

    PIPE ROW(USER_OBJ_TYPE(rec.UserID, 
         rec.UserName, 
         rec.UserStatus, 
         vTrans.TransactionDate, 
         vTtans.TransactionAmt)); 
end MainFunction 

運行這種代碼的僞代碼需要很長的時間,因爲表A和表B是一個非常大的表,我只得到從表中每條記錄1項。

我想創建一個臨時表(TempTableA,TempTableB)內的臨時存儲所有基於startdate和enddate的記錄,以便當我嘗試檢索每個rec的TransactionDate和金額時,我會只能引用TempTables(小於TableA和TableB)。

我也想考慮如果在TableA和TableB中找不到UserID。所以基本上,當TableA和TableB中沒有找到記錄時,我也希望輸出中有條目,但表示用戶處於非活動狀態。

謝謝你的一切幫助。

+1

爲什麼不優化用於每個表的SQL?如果您只在每個選擇中獲得單行,那麼這意味着您的用戶標識是唯一的。你有這個專欄的(唯一)索引嗎?如果不是,你應該添加一個(或甚至一個主鍵)。基於唯一索引檢索單個行將非常快(並且幾乎與表的大小無關) –

+0

您的其他僞代碼非常垃圾。這是一個不會編譯的東西的大雜燴。如果您希望有人爲您編寫代碼,則應該發佈實際的完整需求,而不是讓人們從輕鬆的PL/SQL中猜測它們。當然,受訪者對你的工作沒有作用,但也許有人會感到特別慷慨。 – APC

回答

2

可能會更好做,在一個查詢,例如:

Select UserTable.UserID, UserTable.UserName, UserTable.UserStatus 
     ,TableA.TransactionDate AS ATransactionDate 
     ,TableA.Amount   AS AAmount 
     ,TableB.TransactionDate AS BTransactionDate 
     ,TableB.Amount   AS BAmount 
from UserTable 
left join TableA 
    on (UserTable.UserID = TableA.UserID) 
left join TableB 
    on (UserTable.UserID = TableB.UserID) 
where UserTable.EntryDate between startdate and enddate 
3

SQL是一個基於集合的語言。執行一個返回所需行的語句比執行多個返回單個行的語句要高效得多。

這是一次獲取所有行的方法。它使用一個公共表格表達式,因爲你閱讀了整個UserTable,你應該只做一次。

with cte as 
    (select UserID 
     , UserStatus 
    from UserTable) 
select cte.UserID 
     , cte.UserStatus 
     , TableA.TransactionDate 
     , TableA.Amount 
from cte join TableA 
    on (cte.UserID = TableA.UserID) 
where cte.UserStatus = 'A' 
and TableA.TransactionDate between startdate and enddate 
union 
select cte.UserID 
     , cte.UserStatus 
     , TableB.TransactionDate 
     , TableB.Amount 
from cte join TableB 
    on (cte.UserID = TableB.UserID) 
where cte.UserStatus != 'A' 
and TableB.TransactionDate between startdate and enddate 

順便說一句,小心使用臨時表。它們不像T-SQL中的臨時表。它們是永久性的堆表,它只是他們的數據而已。這意味着填充臨時表是一個昂貴的過程,因爲數據庫將所有這些行寫入磁盤。因此,我們需要確定,通過從臨時表中讀取數據集而獲得的性能增益值得所有這些寫入的開銷。

這肯定不會是你的代碼的情況。事實上,性能問題的答案實際上是「使用全局臨時表」,至少在Oracle中不是這樣。更好的查詢是要走的路,特別是擁抱集合的喜悅!

+0

謝謝@APC。我感謝你的幫助:) 我有其他的情況需要考慮。 我忘記考慮在TableA和TableB中找不到記錄的情況(請在我的問題中查看我更新的僞代碼) 對於混淆感到抱歉。 – bacaviteno