同一 INSERT 期间另一列中序列列的参考值

Posted

技术标签:

【中文标题】同一 INSERT 期间另一列中序列列的参考值【英文标题】:Reference value of serial column in another column during same INSERT 【发布时间】:2012-09-08 02:58:10 【问题描述】:

我有一个带有 SERIAL 主键的表,还有一个 ltree 列,我希望它的值是这些主键的串联。例如

id | path
----------
1    1
2    1.2
3    1.2.3
4    1.4
5    1.5

我很好奇是否有办法在一个查询中进行这样的插入,例如

INSERT INTO foo (id, ltree) VALUES (DEFAULT, THIS.id::text)

我可能在这里超出了范围,并试图在一个查询中完成我应该在两个查询中执行的操作(在事务中分组)。

【问题讨论】:

这条路径看起来不太可查询.. 我的路径值基于此:***.com/a/607379/39529 PostgreSQL 具有递归、公用表表达式,比您的路径解决方案/解决方法更容易和更快。 【参考方案1】:

您可以使用 CTE 从序列中检索值一次重复使用它

WITH cte AS (
   SELECT nextval('foo_id_seq') AS id
   )
INSERT INTO foo (id, ltree)
SELECT id, '1.' || id
FROM   cte;

CTE with a data-modifying command 需要 Postgres 9.1 或更高版本。

如果您不确定序列的名称,请使用 pg_get_serial_sequence() 改为:

WITH i AS (
   SELECT nextval(pg_get_serial_sequence('foo', 'id')) AS id
   )
INSERT INTO foo (id, ltree)
SELECT id, '1.' || id
FROM   i;

如果表名“foo”在数据库中的所有模式中可能不是唯一的,请对其进行模式限定。如果任何名称的拼写不标准,则必须双引号:

pg_get_serial_sequence('"My_odd_Schema".foo', 'id')


快速测试表明@Mark's idea 和lastval() 可能也可以工作:

INSERT INTO foo (ltree) VALUES ('1.' || lastval());

您可以将id 排除在查询之外,serial 列将被自动分配。没有区别。

行之间不应存在竞争条件。我quote the manual:

currval

返回nextval 在当前会话中为此序列最近获得的值。 (如果nextval有 在本次会议中从未为此序列调用过。)因为这是 返回一个会话本地值,它给出一个可预测的答案是否 或者自当前会话以来没有其他会话执行nextval 做了。

此函数需要序列的USAGESELECT 权限。

lastval

返回当前会话中nextval 最近返回的值。此函数currval 相同,除了 将序列名称作为它所引用的参数 序列nextval 最近应用于当前会话。 如果尚未调用 nextval,则调用 lastval 是错误的 当前会话。

此函数需要USAGESELECT 对上次使用的序列的权限。

我的大胆强调。

但是,作为@Bernard commented,它毕竟可以失败:不能保证填充默认值(并且在过程中调用nextval()之前 调用lastval() 来填充第二列ltree。所以坚持第一个解决方案和nextval() 以确保。

【讨论】:

是否保证会先调用nextval()来查找下一个主键,这样lastval()就不会报错? 您的第二个建议会在 PostgreSQL 9.5 上引发 55000 ERROR: lastval is not yet defined in this session @Bernard:感谢您的纠正,我相应地更新了。添加了一种在不知道序列名称的情况下的方法。【参考方案2】:

这在我的测试中有效:

INSERT INTO foo (id, ltree) VALUES (DEFAULT, (SELECT last_value from foo_id_seq));

我认为如果两个 INSERT 同时发生,则存在竞争条件,因为这引用了最后一个序列值,而不是当前行。我个人更倾向于这样做(伪代码):

my $id = SELECT nextval('foo_id_seq');
INSERT INTO foo (id, ltree) VALUES ($id, '$id');

【讨论】:

以上是关于同一 INSERT 期间另一列中序列列的参考值的主要内容,如果未能解决你的问题,请参考以下文章

将时间序列列更改为日期

如何在同一查询的另一列中引用聚合列?

使用同一 Dataframe 中另一列的 int 作为索引获取列中的列表值

如果同一表的另一列中存在值,如何找到对应的列值

pandas 判断某一列数据是不是在另一列中

删除同一列或连续行的另一列中具有特定值和缺失值的行