2014-08-29 133 views
0

我有一個數據庫表,我需要運行UPDATE語句。這個表格有大約250,000條記錄,所以優化的性能很重要。幫助處理複雜的SQL UPDATE語句

這裏是相關的數據庫模式和一些示例數據。

 
audit_logs 
-- id -- ticket_id -- ip_address  -- created_at     -- 
-- 10 -- 100  -- 100.101.102.103 -- 2014-08-22 11:17:28.325844 -- 
-- 11 -- 100  -- 100.101.102.103 -- 2014-08-23 12:18:28.325844 -- 
-- 12 -- 101  -- 200.1.2.3  -- 2014-08-24 13:19:28.325844 -- 
-- 13 -- 101  -- 201.2.3.4  -- 2014-08-25 14:20:28.325844 -- 
-- 14 - 101  -- 202.3.4.5  -- 2014-08-26 15:21:28.325844 -- 
-- 15 - 102  -- 102.12.34.56 -- 2014-08-27 16:22:28.325844 -- 

這是我需要做的。對於任何具有超過1個IP地址的記錄的ticket_id,我需要將除第一個IP地址以外的每個IP地址的ticket_id設置爲NULL。以上是上述數據的示例結果。

 
audit_logs 
-- id -- ticket_id -- ip_address  -- created_at     -- 
-- 10 -- 100  -- 100.101.102.103 -- 2014-08-22 11:17:28.325844 -- 
-- 11 -- 100  -- 100.101.102.103 -- 2014-08-23 12:18:28.325844 -- 
-- 12 -- 101  -- 200.1.2.3  -- 2014-08-24 13:19:28.325844 -- 
-- 13 -- NULL  -- 201.2.3.4  -- 2014-08-25 14:20:28.325844 -- 
-- 14 - NULL  -- 202.3.4.5  -- 2014-08-26 15:21:28.325844 -- 
-- 15 - 102  -- 102.12.34.56 -- 2014-08-27 16:22:28.325844 -- 

因此,可以有多張記錄具有相同的票據。但是,如果有一個以上的IP地址與一張票相關聯,則每個帶有除第一個IP地址以外的IP地址的記錄都需要清空。

我正在使用的實際RDBMS是Postgres。最簡單的方法是什麼?謝謝大家。

+0

如何確定哪一行是'第一';創建日期? – sirlark 2014-08-29 21:52:23

+0

它可能是兩件事之一。給定ticket_id的最小'created_at'時間或最小的'id'值。兩者訂購應產生相同的結果。 – WhiteWulfTech 2014-08-29 22:02:43

+0

不,記錄11的ticket_id不應該爲空,因爲記錄10和11的IP地址值是相同的。我只想在IP地址不同時清空票據。 – WhiteWulfTech 2014-08-29 22:03:26

回答

1

不幸的是Postgres還不支持count(distinct ..)作爲窗口函數所以這是一個有點比需要的更復雜:

update audit_logs 
    set ticket_id = null 
from (
    select a.id, 
     a.ticket_id, 
     row_number() over (partition by a.ticket_id order by a.created_at) as rn 
    from audit_logs a 
    join (
    select ticket_id 
    from audit_logs 
    group by ticket_id 
    having count(distinct ip_address) > 1 
) t on t.ticket_id = a.ticket_id 
) x 
where x.id = audit_logs.id 
and x.rn > 1; 

SQLFiddle:http://sqlfiddle.com/#!15/a632c/1

最裏面選擇(化名t)獲得的所有ticket_id那有多個IP地址。然後再與基表連接來計算行數。然後在update中使用該結果查找應更新的行。

不確定性能,它很大程度上取決於最內層選擇將返回多少行。

+0

這不僅工作,它運行了大約6秒!在250,000箇中有約140,000個記錄被擊中。我運行了驗證查詢,一切進展順利。謝謝! – WhiteWulfTech 2014-08-29 22:18:25

0

嘗試這樣的事情入手,優化後

UPDATE audit_logs O 
SET ticket_id = NULL 
WHERE (
    SELECT count(distinct ip_address) 
    FROM audit_logs I WHERE I.ticket_id = O.ticket_id 
) > 1 AND id <> (
    SELECT DISTINCT ON (id) id 
    FROM audit_logs I WHERE I.ticket_id = O.ticket_id 
) AND ip_address <> (
    SELECT DISTINCT ON (ip_address) ip_address 
    FROM audit_logs I WHERE I.ticket_id = O.ticket_id 
) 

附:我的PostgreSQL是生鏽的,所以語法可能有點偏離......沒有在我的家用機器上安裝PostgreSQL來檢查,對不起。