簡體   English   中英

在 Oracle 中根據對自身的自聯接查詢更新表中的值

[英]Update values in a table based on a self-join query to itself in Oracle

我有一個表,其中包含制造項目的記錄事件。 我們將每個事件視為具有 2 個狀態,這些狀態基於相同項目的先前記錄事件的詳細信息和計算。 因此,我開發了一個 SELECT 查詢,它使用多個自聯接來分析與每個事件相關的先前事件的因素,並計算狀態。 但是因為這個查詢相對較慢,我添加了 2 個狀態列,我想在事件發生后用計算的狀態更新列。 通過這種方式,我可以稍后快速獲得有關狀態列的報告,而不必每次都運行所有計算。

這是我的桌子:

CREATE TABLE ItemLog
(
   ItemID decimal(11) NOT NULL,
   MessageTime DATE NOT NULL, 
   Temperature float(7), 
   Voltage float(7),
   Status1 VARCHAR2(10 BYTE), 
   Status2 VARCHAR2(10 BYTE),
   CONSTRAINT "ItemLog_PK" PRIMARY KEY ("ItemID ", "MessageTime ")
);

我的 SELECT 計算查詢是這樣的:

SELECT ItemID, MessageTime, 
    CASE WHEN A.Voltage<B.Voltage and A.Voltage<C.Avg_Voltage and C.SD_Voltage<5 THEN 'Good' ELSE 'Bad' END Calculated_Status1, 
    CASE WHEN A.Temperature<B.Temperature and A.Temperature>C.Temperature and C.SD_Temperature>10 THEN 'Good' ELSE 'Bad' END Calculated_Status2 
FROM ItemLog A,
   (SELECT F.ItemID,
        F.MessageTime Key_MessageTime,
        S.Voltage,
        S.Temperature
    FROM ItemLog F,
        ItemLog S
    WHERE F.ItemID=S.ItemID 
        and S.MessageTime=
            SELECT MAX(MessageTime)
            FROM ItemLog
            WHERE ItemID=F.ItemID
               and MessageTime<F.MessageTime
               and Voltage<12
               and Temperature<125
    ) B,  -- Returns the Voltage and Temperature from the prior time it was <12 and <125
   (SELECT K.ItemID, K.MessageTime,
        AVG(L.Temp) Avg_Temperature, STDDEV(L.Temperature) SD_Temp, 
        AVG(L.Voltage) Avg_Voltage, STDDEV(L.Voltage) SD_Voltage 
    FROM ItemLog K,
        ItemLog L
    WHERE K.ItemID=L.ItemID 
        and L.MessageTime=
            SELECT MAX(MessageTime)
            FROM ItemLog
            WHERE ItemID=K.ItemID
               and MessageTime<K.MessageTime
    GROUP BY K.ItemID, K.MessageTime
     ) C  -- Returns the Voltage and Temperature stats from all prior messages
   (SELECT ItemID 
    FROM ItemLog
    WHERE Voltage>40
     ) D  -- Returns all ItemID where Voltage was ever >40, to exclude them
WHERE A.ItemID=B.ItemID and A.MessageTime=B.MessageTime
  and A.ItemID=C.ItemID and A.MessageTime=C.MessageTime
  and A.ItemID=D.ItemID(+) and D.ItemID IS NULL

所以,問題是,如何將表中的 Status1 和 Status2 列更新為Calculated_Status1 和Calculated Status2 列? 我嘗試將我的計算查詢通過 2 個主鍵連接到表中,但我收到“ORA-01779:無法修改映射到非鍵保留表的列”錯誤。

UPDATE ( 
    SELECT U.*,
        V.Calculated_Status1
        V.Calculated_Status2
    FROM ItemLog U,
        ( <calculation query above> ) V
    WHERE U.ItemID=V.ItemID and U.MessageTime=V.MessageTime )
SET U.Status1=V.CalculatedStatus1,
    U.Status2=V.CalculatedStatus2

我可以想象一個帶有SET Status1=(SELECT...直接的方式來做到這一點?

我希望您正在尋找的解決方案可以使用 MERGE 語句提供。 我希望您發布的查詢是正確的。 我已經在查詢之上構建了解決方案。 如果這有幫助,請告訴我。

MERGE INTO ItemLog it USING
(SELECT ItemID, MessageTime, 
    CASE WHEN A.Voltage<B.Voltage and A.Voltage<C.Avg_Voltage and C.SD_Voltage<5 THEN 'Good' ELSE 'Bad' END Calculated_Status1, 
    CASE WHEN A.Temperature<B.Temperature and A.Temperature>C.Temperature and C.SD_Temperature>10 THEN 'Good' ELSE 'Bad' END Calculated_Status2 
FROM ItemLog A,
   (SELECT F.ItemID,
        F.MessageTime Key_MessageTime,
        S.Voltage,
        S.Temperature
    FROM ItemLog F,
        ItemLog S
    WHERE F.ItemID=S.ItemID 
        and S.MessageTime=
            SELECT MAX(MessageTime)
            FROM ItemLog
            WHERE ItemID=F.ItemID
               and MessageTime<F.MessageTime
               and Voltage<12
               and Temperature<125
    ) B,  -- Returns the Voltage and Temperature from the prior time it was <12 and <125
   (SELECT K.ItemID, K.MessageTime,
        AVG(L.Temp) Avg_Temperature, STDDEV(L.Temperature) SD_Temp, 
        AVG(L.Voltage) Avg_Voltage, STDDEV(L.Voltage) SD_Voltage 
    FROM ItemLog K,
        ItemLog L
    WHERE K.ItemID=L.ItemID 
        and L.MessageTime=
            SELECT MAX(MessageTime)
            FROM ItemLog
            WHERE ItemID=K.ItemID
               and MessageTime<K.MessageTime
    GROUP BY K.ItemID, K.MessageTime
     ) C  -- Returns the Voltage and Temperature stats from all prior messages
   (SELECT ItemID 
    FROM ItemLog
    WHERE Voltage>40
     ) D  -- Returns all ItemID where Voltage was ever >40, to exclude them
WHERE A.ItemID=B.ItemID and A.MessageTime=B.MessageTime
  and A.ItemID=C.ItemID and A.MessageTime=C.MessageTime
  and A.ItemID=D.ItemID(+) and D.ItemID IS NULL)z
ON
(it.ItemID = z.ItemID AND it.MessageTime = z.MessageTime)
WHEN MATCHED THEN
UPDATE SET it.STATUS1 = z.Calculated_Status1,
       it.STATUS2 = z.Calculated_Status2;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM