WHERE "id" = nextval(seq) 无法正常工作

WHERE "id" = nextval(seq) doesn't work properly

Table: test_seq

id (varchar(8)) raw_data (text)
cd_1 'I'm text'
cd_2 'I'm more text'
CREATE SEQUENCE cd_seq CYCLE START 1 MAXVALUE 2;
ALTER TABLE test_seq
ALTER COLUMN id SET DEFAULT ('cd_'||nextval('cd_seq'))::VARCHAR(8);

UPDATE test_seq
SET raw_data = 'New Text'
WHERE "id" = 'cd_'||nextval('cd_seq')::VARCHAR(8);

我正在制作一个 table,它将存储原始数据作为短期备份,如果由于某种原因数据摄取失败,我们需要返回而不再次提取它。我正在尝试设置一种方法,以便在我们达到 ID 限制时替换记录。

所以如果我想要 table 中的 25 条记录,当 SEQUENCE 从最大值 ('cd_25') 回滚到 ('cd_1') 时,我想要 raw_data更新到新数据。

我已经为第一个插入提出了序列和默认值,但我的更新命令不会更新记录,即使“id”匹配 'cd_'||nextval('cd_seq'),它有时会一次更新 9 行。

我检查了“id”和 'cd_'||nextval('cd_seq') 的值,它们似乎匹配,但 WHERE 无法正常工作。

我是不是漏掉了什么,还是把事情复杂化了? 谢谢

虽然我同意 Adrian Klaver 的评论,即由于序列的工作方式,这种方法非常脆弱,如果:

  1. 您可以确保列默认值是对序列的唯一调用
  2. 如果插入失败,您不介意跳过行,但序列仍会递增其值
  3. 您可以确保所有插入都处理如下冲突

这可行。 不要试图通过更新现有行来插入数据——顺便说一下,这会迫使你预先填充 table——只是实际插入它并处理冲突。

insert into test_seq
(text_column)
values
('e')
on conflict(id) do update set text_column=excluded.text_column;

与我在测试中所做的当前更新方法相比,这还允许您一次插入多行(最多 table 的最大大小,序列的长度)下面。

drop sequence if exists cd_seq cascade;
create sequence cd_seq cycle start 1 maxvalue 4;

drop table if exists test_seq cascade;
create table test_seq 
(id text primary key default ('cd_'||nextval('cd_seq'))::VARCHAR(8),
text_column text);

insert into test_seq
(text_column)
values
('a'),
('b'),
('c'),
('d')
on conflict(id) do update set text_column=excluded.text_column;
select id, text_column from test_seq;
--  id  | text_column
--------+-------------
-- cd_1 | a
-- cd_2 | b
-- cd_3 | c
-- cd_4 | d
--(4 rows)
insert into test_seq
(text_column)
values
('e'),
('f')
on conflict(id) do update set text_column=excluded.text_column;
select id, text_column from test_seq;
--  id  | text_column
--------+-------------
-- cd_3 | c
-- cd_4 | d
-- cd_1 | e
-- cd_2 | f
--(4 rows)

如果您尝试插入比序列长度更多的行,您将得到

ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time

HINT: Ensure that no rows proposed for insertion within the same command have duplicate constrained values.

如果在您当前的解决方案中,您为 update 提供了一个源 table 以从中获取多行,并且它们的数量也超过了序列长度,则不会造成问题 - 成对冲突你只会得到最后一个。这是您的更新,已修复(但仍需要预先填充您的 table):

with new as (
    select ('cd_'||nextval('cd_seq'))::VARCHAR(8) id,'g' text_column union all 
    select ('cd_'||nextval('cd_seq'))::VARCHAR(8) id,'h' text_column union all 
    select ('cd_'||nextval('cd_seq'))::VARCHAR(8) id,'i' text_column union all 
    select ('cd_'||nextval('cd_seq'))::VARCHAR(8) id,'j' text_column union all 
    select ('cd_'||nextval('cd_seq'))::VARCHAR(8) id,'k' text_column)
update test_seq old
set text_column=new.text_column
from new
where old.id=new.id;