在没有主键的情况下更新/删除列中的任意行

问题描述 投票:1回答:1

我正在构建一个工具,它将显示给定的PostgreSQL数据库(客户端的遗留应用程序)中的所有表,然后用户将深入挖掘,并可以查看给定表中的所有数据。它本质上是一个数据库查看器。

下一步将允许用户以与Airtable中的数据更新方式类似的方式更新每一行。

虽然对于大多数列我会有主键,所以我可以用来构建适当的Update ... where ID=?语句,我意识到可能并非总是如此。例如,对于某些连接表,我没有ID或任何其他主键。

我仍然希望具有用户查看从这些列显示的数据网格的功能,通过单击鼠标选择一行并提供新值。

PostgreSQL曾经使用OID来为这种情况单点识别行,但即使对于我正在处理的遗留数据库,情况也不再如此。

我能想到的唯一解决方案是使用偏移/排序顺序来确定要更新哪一行,但如果在此期间排序更改或用户删除/添加某些行,则会导致竞争条件。

我有什么想法可以更新这样的“匿名”行吗?

sql postgresql
1个回答
3
投票

Postgres中的每个表都有一个系统列ctid,它明确地标识了一行。例:

drop table if exists my_table;
create table my_table(id int, str text);
insert into my_table values
(1, 'one'),
(1, 'two'),
(2, 'one');

select ctid, *
from my_table;

 ctid  | id | str 
-------+----+-----
 (0,1) |  1 | one
 (0,2) |  1 | two
 (0,3) |  2 | one
(3 rows)

您可以使用deleteupdate中的列:

delete from my_table
where ctid = '(0,2)'
returning *

 id | str 
----+-----
  1 | two
(1 row)

DELETE 1

但请注意,根据ctid,无法保证一行始终具有相同的the documentation:

CTID

行版本在其表中的物理位置。请注意,尽管可以使用ctid非常快速地定位行版本,但如果行的ctid被VACUUM FULL更新或移动,则行的ctid将会改变。因此,ctid作为长期行标识符是无用的。应该使用OID,甚至更好的用户定义的序列号来标识逻辑行。

© www.soinside.com 2019 - 2024. All rights reserved.