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 的评论,即由于序列的工作方式,这种方法非常脆弱,如果:
- 您可以确保列默认值是对序列的唯一调用
- 如果插入失败,您不介意跳过行,但序列仍会递增其值
- 您可以确保所有插入都处理如下冲突
这可行。
不要试图通过更新现有行来插入数据——顺便说一下,这会迫使你预先填充 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;
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 的评论,即由于序列的工作方式,这种方法非常脆弱,如果:
- 您可以确保列默认值是对序列的唯一调用
- 如果插入失败,您不介意跳过行,但序列仍会递增其值
- 您可以确保所有插入都处理如下冲突
这可行。 不要试图通过更新现有行来插入数据——顺便说一下,这会迫使你预先填充 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;