2009-12-15 112 views
3
CREATE TABLE Landmark 
(
    Indexc NUMBER 
    Birth DATE 
    Address VARCHAR2(50 BYTE) 
    City VARCHAR2(30 BYTE) 
    State CHAR(2 BYTE) 
    Zip VARCHAR2(15 BYTE) 
    ... 
    Other properties 
) 

ALTER TABLE Landmark ADD (
    CONSTRAINT Landmark_PK PRIMARY KEY (Indexc, Birth)); 

CREATE TABLE MapPoint 
(
    Indexc NUMBER 
    Longitude FLOAT(126) 
    Latitude FLOAT(126) 
    BuildDate DATE 
) 

ALTER TABLE MapPoint ADD (
    CONSTRAINT MapPoint_FK FOREIGN KEY (Indexc) REFERENCES Landmark (Indexc)); 

「地標」表包含可隨時移動的地標列表。 MapPoint表格保存這些地標的經度和緯度。任何時候某個地​​標的屬性發生變化時,都會在該地標的Landmark表中插入一個新行,並且新的出生日期將無法使用該地址。用第二行到最後一行的數據更新最後一行

我有一個腳本將在MapPoint表中爲所有沒有物理移動的地標設置BuildDate爲空,我試圖編寫一個UDPATE語句來重用最後一行的地址。以下是接近我想要的,但不起作用,因爲最內層的子查詢不會與更新語句相關聯。我得到ORA-00904:「lm2」。「索引」:無效的標識符。

UPDATE Landmark lm1 
    SET (Address, City, State, Zip) = (
    SELECT Address, City, State, Zip 
    FROM Landmark lm2 
    WHERE lm2.Indexc = lm1.Indexc 
     AND lm2.birth = (
     SELECT MIN(Birth) 
     FROM (
     SELECT Birth 
      FROM Landmark lm3 
      WHERE lm3.Indexc = lm2.Indexc 
      ORDER BY Birth DESC) 
     AND ROWNUM < 3)) 
WHERE Indexc IN (
    SELECT Indexc 
    FROM MapPoint 
    WHERE BuildDate IS NULL); 

樣品之前:

Indexc     Birth  Address   City State  Zip 
------ ---------------------- ------------ ----------- ----- ----- 
    45 8/16/2009 4:46:21 AM 123 Main St Springfield  PA 84679 
    45 8/18/2009 7:20:27 PM 123 Main St Springfield  PA 84679 
    45 8/20/2009 9:01:44 PM 456 Smith Ln Springfield  PA 84153 
    45 10/31/2009 12:29:07 AM 

樣品後:

Indexc     Birth  Address   City State  Zip 
------ ---------------------- ------------ ----------- ----- ----- 
    45 8/16/2009 4:46:21 AM 123 Main St Springfield  PA 84679 
    45 8/18/2009 7:20:27 PM 123 Main St Springfield  PA 84679 
    45 8/20/2009 9:01:44 PM 456 Smith Ln Springfield  PA 84153 
    45 10/31/2009 12:29:07 AM 456 Smith Ln Springfield  PA 84153 
+0

您可以發佈一些示例數據以及更新後的樣子嗎? – Quassnoi 2009-12-15 17:04:00

回答

0

我取代 「指標」 與 「indexc」,因爲指數是不是在oracle中有效的列名。我認爲這是做你想要的,但:

UPDATE Landmark lm1 
SET (Address, City, State, Zip) = (
SELECT Address, City, State, Zip 
    FROM Landmark lm2 
    WHERE lm2.Indexc = lm1.Indexc 
    AND lm2.birth = (
    SELECT MAX(Birth) 
     FROM Landmark lm3 
     WHERE lm3.Indexc = lm2.Indexc 
     and lm3.birth < lm2.birth)) 
WHERE (indexc,birth) in (
     select indexc, max(birth) 
     from Landmark 
     where Indexc IN (
      SELECT Indexc 
      FROM MapPoint 
      WHERE BuildDate IS NULL)); 
+0

這不起作用。它更新所有的行而不是最新的行。在某些情況下,它更新第二個最新版本,然後更新可能導致問題的最新版本。 – 2009-12-16 15:34:02

+0

嘗試使用索引和出生過濾的新版本 – 2009-12-16 15:40:43

1

這完美的作品。雖然它對於第n個最新的項目不是很可擴展的。

UPDATE Landmark lm1 
    SET (Address, City, State, Zip) = (
    SELECT Address, City, State, Zip 
    FROM Landmark lm2 
    WHERE lm2.Indexc = lm1.Indexc 
     AND lm2.birth = (
     SELECT MAX(Birth) 
     FROM Landmark lm3 
     WHERE lm3.Indexc = lm2.Indexc 
     AND lm3.birth < (
     SELECT MAX(Birth) 
      FROM Landmark lm4 
      WHERE lm4.Indexc = lm3.Indexc))) 
WHERE Indexc IN (
    SELECT Indexc 
    FROM MapPoint 
    WHERE BuildDate IS NULL) 
    AND Birth = (
    SELECT MAX(Birth) 
    FROM Landmark lm2 
    WHERE lm2.Indexc = lm1.Indexc); 
1

此解決方案使用解析函數。代碼看起來稍微多餘的,但成本較低,至少在我的測試數據庫,可能是因爲有較少的子查詢:

update landmark L1 set (address, city, state, zip) = 
    (select address, city, state, zip from 
     (select last_value(address ignore nulls) over (partition by cindex order by birth) address, 
       last_value(city ignore nulls) over (partition by cindex order by birth) city, 
       last_value(state ignore nulls) over (partition by cindex order by birth) state, 
       last_value(zip ignore nulls) over (partition by cindex order by birth) zip, 
       cindex, birth 
      from landmark) L2 
     where l1.cindex = l2.cindex and l2.birth = l1.birth)  
where CIndex IN (
SELECT CIndex 
    FROM MapPoint 
    WHERE BuildDate IS NULL) 
    and address is null 

基本上它說,獲取所有從表和每行的行選擇地址值如果不爲空或最後一個非空值(如果它們是),則更新那些需要更新的行的值。

相關問題