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

时间:2018-03-30 16:35:23

标签: sql postgresql

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

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

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

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

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

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

任何想法如何更新此类"匿名"行?

1 个答案:

答案 0 :(得分:4)

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符合<services> <service name="themepark.Service1"> <clear /> <endpoint binding="basicHttpBinding" contract="themepark.IService1" /> </service> </services> the documentation:

  

CTID

     

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