2017-08-10 52 views
2

更新來自SELECT查詢我想UPDATE在維度表client一些列根據event表數據:重複鍵衝突在Vertica的

UPDATE client AS c 
SET 
    some_attr_last_value = last_attr_values.value 
FROM (

    SELECT 
    l.client_id, 
    value, 
    ROW_NUMBER() OVER (PARTITION BY l.client_id ORDER BY timestamp DESC) AS num 
    FROM event AS l 
    WHERE 
    timestamp > DATE_TRUNC('month', NOW() - INTERVAL '1 month') 

) AS last_attr_values 

WHERE 
    last_attr_values.num = 1 AND 
    c.client_id = last_attr_values.client_id AND 
    c.some_attr_last_value <> last_attr_values.value; 

我已經有類似上面的幾個疑問:他們是更新等欄目以同樣的方式(只與其他欄目),並運作良好。但有一個查詢會產生錯誤:

ERROR 6745: Duplicate key values: 'client_id=…' -- violates constraint '… .client.C_PRIMARY'

但是我不會嘗試更改client_id。爲什麼發生這個錯誤?

我檢查了client表,但它沒有重複。 ANALYZE_CONSTRAINTS('client')也不返回違規。

版本是7.2.2-1。

+0

那張桌子上有沒有觸發器?我不熟悉vertica,所以我只是把它扔在那裏。 –

+0

據我所知,Vertica不支持觸發器。 – Timurib

+1

你可以添加'事件'和'客戶'的CREATE TABLE,以及確切的UPDATE語句 - 以及(如果適用的話),您在同一事務中激發的一堆以前的UPDATE語句(假設您已關閉自動提交或觸發了BEGIN TRANSACTION之前)? – marcothesane

回答

3

問題不在於您的客戶表與您的內部選擇一致。

SELECT 
    l.client_id, 
    value, 
    ROW_NUMBER() OVER (PARTITION BY l.client_id ORDER BY timestamp DESC) AS num 
    FROM event AS l 
    WHERE 
    timestamp > DATE_TRUNC('month', NOW() - INTERVAL '1 month') 

這是什麼在SELECT,確保您有一個記錄每個客戶端?

讓我們假設你有多個事件,你有多個客戶端的事件。

  • CLIENT_ID 1 10:00
  • CLIENT_ID 1 10:05
  • CLIENT_ID 9 10:05
  • CLIENT_ID 9 10:06
  • CLIENT_ID 1 10:07

由於您的窗口功能按時間戳排序

ROW_NUMBER() OVER (PARTITION BY l.client_id ORDER BY timestamp DESC) AS num 

你會得到

  • CLIENT_ID 11
  • CLIENT_ID 1 2
  • CLIENT_ID 9 1
  • CLIENT_ID 9 2
  • CLIENT_ID 11 < ----第二CLIENT_ID 1的ROW_NUMBER 1!

我相信你需要在你的ORDER BY中包含Client_id以使你的查詢工作。


更新:一段時間後,又發生了錯誤。我試圖使用上述解決方案,但不幸的是它沒有幫助。該錯誤僅使用臨時表克服:

CREATE LOCAL TEMPORARY TABLE last_values ON COMMIT PRESERVE ROWS 
AS SELECT client_id, value FROM (
    SELECT 
    l.client_id, 
    value, 
    ROW_NUMBER() OVER (PARTITION BY l.client_id ORDER BY timestamp DESC) AS num 
    FROM event AS l WHERE timestamp > DATE_TRUNC('month', NOW() - INTERVAL '1 month') 
) last_values WHERE last_values.num = 1; 

UPDATE client AS c 
SET some_attr_last_value = last_values.value 
FROM last_values 
WHERE c.client_id = last_values.client_id AND c.some_attr_last_value <> last_attr_values.value 

DROP TABLE last_values; 

所以,雖然問題解決了,但我沒有找到它的確切原因。

+0

對不起,但我不能複製你的例子:https://pastebin.com/raw/a3kctbei - 所有'client_id'被自己的框架分割,並順序排列,沒有重複的對。也許我錯過了什麼? 不幸的是,我不能只將時間戳中的一個排序替換爲client_id,因爲我需要確切的最後一個值。 – Timurib

+0

嘗試使用client_id和timestamp命令。不是一個而是另一個。當兩個數據集中都沒有重複時,我遇到了這個問題,問題在於查詢優化引擎無法知道密鑰是否是唯一的,因此對此抱怨。 –

+0

我很困惑,但幾個小時前,錯誤_just沒有任何更改query_。我們成功完成了所有時間的所有行的更新(沒有上個月的條件),並且沒有找到重複項。 我終於明白你的解決方案,但現在我無法檢查它。無論如何,我很感激您的信息,並認爲這可能對其他人有幫助,所以我認爲答案應該被標記爲已接受。謝謝! – Timurib

1

Vertica通常會在SELECT時間檢查約束,而不是在您更新時。檢查你的餐桌上的dups。

我認爲Vertica的最新版本確實有一些選項可用於檢查INSERTUPDATE但這不是默認設置。

+0

是的,我已經檢查了表,它不包含重複項(每個'client_id'只包含在'client'中一次)。 – Timurib