Vertica 中 UPDATE FROM SELECT 查询的重复键违规

Duplicate key violation on UPDATE FROM SELECT query in Vertica

我想 UPDATE 根据 event table 数据 table client 维度中的某些列:

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 table,但没有重复。 ANALYZE_CONSTRAINTS('client')也returns没有违规。

版本为 7.2.2-1。

Vertica 通常在 SELECT 时间检查约束,而不是在您更新时。检查你的 table 是否有重复。

我认为最新版本的 Vertica 现在确实有一些选项可以在 INSERTUPDATE 进行检查,但这不是默认设置。

问题不在于你的客户table,而在于你的内心select。

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

因为你的window函数是按时间戳排序的

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

你会得到

  • Client_id 1 1
  • Client_id 1 2
  • Client_id 9 1
  • Client_id 9 2
  • Client_id 1 1 <---- 第二个 Client_id 1,Row_number 为 1!

我认为您需要在 ORDER BY 中包含 Client_id 才能使查询生效。


更新: 一段时间后错误再次发生。我尝试使用上述解决方案,但不幸的是它没有帮助。仅使用临时 table:

克服了错误
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;

所以虽然问题解决了,但是我并没有找到具体原因。