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 现在确实有一些选项可以在 INSERT
和 UPDATE
进行检查,但这不是默认设置。
问题不在于你的客户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;
所以虽然问题解决了,但是我并没有找到具体原因。
我想 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 现在确实有一些选项可以在 INSERT
和 UPDATE
进行检查,但这不是默认设置。
问题不在于你的客户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;
所以虽然问题解决了,但是我并没有找到具体原因。