2009-04-16 34 views
2

我遇到了一個問題,我花了很多時間試圖解決這個問題,儘管我有一個解決方案,但它很笨重,涉及到pl/sql處理,我想知道別人可能會提出什麼。檢索當前和最近一次的值(Oracle)

我正在處理一個數據集,每次更改記錄時都會創建一個新行,從而保留歷史記錄。最新的版本將顯示在我們的應用程序中。考慮一個表具有以下數據:

 
Person ID Last_Name Address_line1  Effective_Start_Date Effective_End_Date 
4913  Jones  1 First Street  03-aug-02    31-dec-12 
4913  Cross  1 First Street  01-feb-02    02-aug-02 
4913  Cross  86 Green Avenue  01-mar-01    31-jan-02 
4913  Cross  87 Devonshire Road 01-jan-90    28-feb-02 

作爲報告的一部分,我需要提取其中還有一個給定日期之間改變的細節。例如,假設我想提取當前的address_line1和之前的address_line1以及更改日期(添加新地址時的effective_start_date)。需要注意的是,如果其他列數據發生更改,這也會創建一個新行。例如,在上面的示例中,地址更改後last_name已更改。

不幸的是,查詢必須是通用的,以便它可以作爲報告的一部分運行,不必明確指定有效的開始和結束日期。

希望大家都有道理。希望你們都還在我身邊。因此,考慮到數據集上面,我希望看到我的報告結果如下:

 
Person ID Surname Address_line1 Prev_Address_line1 Effective Start date of New Address Line 1 
4913  Jones 1 First Street 86 Green Avenue  01-feb-02 

我的方法包括處理與PL/SQL和遍歷了相當數量的記錄,但我想知道,這可以在單個sql查詢中完成。

有沒有人有任何想法,這是否可以使用只有SQL?

回答

5
SELECT personID, surname, address_line1, 
     LAG(address_line1) OVER (PARTITION BY personID ORDER BY effectiveDate) AS prev_address_line1 
FROM mytable 
WHERE personID = :myid 
ORDER BY 
     effectiveDate 

要返回的最後一個有效的值,使用:

SELECT * 
FROM (
     SELECT personID, surname, address_line1, 
       LAG(address_line1) OVER (PARTITION BY personID ORDER BY effectiveDate) AS prev_address_line1, 
       ROW_NUMBER() OVER (PARTITION BY personID ORDER BY effectiveDate DESC) AS rn, 
     FROM mytable 
     WHERE personID = :myid 
     ) 
WHERE rn = 1 
0

不能完全明白你的問題。

作爲報告的一部分,我需要提取 已 之間改變一組給定日期的細節。

對戰

Unfortunatey,查詢必須 通用的,因此,它可以作爲報告的一部分 ,即運行。不需要明確指定 的有效開始和結束日期爲 。

1)您的報告是否提供開始日期和結束日期,並查找範圍內的更改? 2)或者你是否在尋找一份關於日期沒有限制的所有變化的綜合報告?

而且

假設姓設定要爲其運行報告的日期內改變。

1)在您預期的結果,你完全忽視了姓氏變更

2的情況)或將是在你的報告另一行。

類型

Person ID Surname Prev_Surname Effective_Start_date_of_New Surname 
4913  Jones Cross   03-aug-02 

3)

或者是更爲複雜,你將捕獲一行的所有變化。

Person ID Surname Prev_Surname Effective_Start_date_of_New Surname Address_line1 Prev_Address_line1 Effective_Start_date_of_New_Address_Line_1 
4913  Jones Cross   03-aug-02       1 First Street 86 Green Avenue  01-feb-02 

對於顯示每個更改的報告以及以前的名稱和地址值。嘗試這個。您可以選擇外部選擇的最後更改並選擇Change_rank = 1

SELECT PERSON_ID, CHANGED, NEW_VAL, OLD_VAL, EFFECTIVE_START_DATE 
     -- The Rank just lets you pick by order of change incase you only want the last change, or last 2 changes 
     ,RANK() OVER (ORDER BY EFFECTIVE_START_DATE DESC) CHANGE_RANK 
    FROM (
      -- A select over Partition for each column where Old_val and New_Val need to be retrieved. 
      -- In this Select the Address Column and Changed Address Are retrieved. 
      SELECT PERSON_ID, 'ADDRESS_LINE1 CHANGE' CHANGED, ADDRESS_LINE1 NEW_VAL 
       ,LEAD (ADDRESS_LINE1) OVER (PARTITION BY PERSON_ID ORDER BY EFFECTIVE_START_DATE DESC) AS OLD_VAL 
       ,EFFECTIVE_START_DATE 
      FROM TMP_RM_TEST 
      -- Usually You want to run a report for a period, Or remove this entire filter 
      WHERE EFFECTIVE_START_DATE BETWEEN TO_DATE (:REPORT_START_DATE, 'YYYYMMDD') 
              AND TO_DATE (:REPORT_END_DATE, 'YYYYMMDD') 
      UNION 
      -- In this Select the Name Column and Changed Name Are retrieved. 
      SELECT PERSON_ID, 'LAST_NAME CHANGE' CHANGED, LAST_NAME NEW_VAL 
       ,LEAD (LAST_NAME) OVER (PARTITION BY PERSON_ID ORDER BY EFFECTIVE_START_DATE DESC) AS OLD_VAL 
       ,EFFECTIVE_START_DATE 
      FROM TMP_RM_TEST 
      WHERE EFFECTIVE_START_DATE BETWEEN TO_DATE (:REPORT_START_DATE, 'YYYYMMDD') 
              AND TO_DATE (:REPORT_END_DATE, 'YYYYMMDD')) 
    -- Since the Partition By lists all changes over Person_ID, Irrespective of whether the Column changed, Filter to Remove Lines where no change was made to the Coloumn monitored 
WHERE NEW_VAL <> OLD_VAL 
ORDER BY CHANGE_RANK