我的用例如下:我正在处理定期数据导入PostgreSQL数据库,其中必须定期导入一些外部数据。
需要注意的是数据的结构可能会从一个导入更改为另一个导入,因此我会在插入新数据之前截断+删除每个导入的所有列。
我想将整个操作包装在一个事务中,所以如果出现问题,事务将被回滚,旧的数据仍然可以访问(两种不同的东西)。< / p>
举个例子,这是数据导入语句的样子:
BEGIN
ALTER TABLE "external_data" DROP "date"
ALTER TABLE "external_data" DROP "column1"
ALTER TABLE "external_data" DROP "column2"
ALTER TABLE "external_data" ADD "date" date DEFAULT NULL
ALTER TABLE "external_data" ADD "column1" text DEFAULT NULL
ALTER TABLE "external_data" ADD "column2" text DEFAULT NULL
ALTER TABLE "external_data" ADD "column3" text DEFAULT NULL
INSERT INTO "external_data" ("date","column1","column2","column3") VALUES ('20170523','Berlin','Chrome','1'),('20170524','Berlin','Chrome','2')
COMMIT
目前无效。 INSERT语句被卡住了,因为当它被调用时,表仍然被锁定在它之前的ALTER TABLE语句中。
在Postgres交易中有没有办法实现这一点,还是应该放弃并去寻求其他解决方案?
答案 0 :(得分:3)
您可以在http://rextester.com/OTU89086
中看到该示例您可以添加多少列(即使您丢弃其他列)也有限制。如果你做了很多,你会得到:
54011: tables can have at most 1600 columns
你可以在这里看到这个问题:
--PostgreSQL 9.6
--'\\' is a delimiter
select version() as postgresql_version;
drop table if exists "external_data";
create table "external_data"(
"date" date,
"column1" integer,
"column2" text,
"column3" boolean
);
BEGIN TRANSACTION;
create or replace function do_the_import()
returns text
language plpgsql as
$body$
begin
ALTER TABLE "external_data" DROP "date";
ALTER TABLE "external_data" DROP "column1";
ALTER TABLE "external_data" DROP "column2";
ALTER TABLE "external_data" DROP "column3";
ALTER TABLE "external_data" ADD "date" date DEFAULT NULL;
ALTER TABLE "external_data" ADD "column1" text DEFAULT NULL;
ALTER TABLE "external_data" ADD "column2" text DEFAULT NULL;
ALTER TABLE "external_data" ADD "column3" text DEFAULT NULL;
INSERT INTO "external_data" ("date","column1","column2","column3") VALUES ('20170523','Berlin','Chrome','1'),('20170524','Berlin','Chrome','2');
return current_timestamp::text;
end;
$body$;
select count(do_the_import()) from generate_series(1,1000);
COMMIT;
答案 1 :(得分:2)
目前无效。 INSERT语句卡住了 因为,当它被调用时,表仍然被ALTER锁定 在它之前的TABLE语句。
不,交易无法以这种方式锁定自己。如果INSERT是由另一个事务启动的,则会被阻塞,而不是已经对该对象进行强锁定的事件。删除列并在同一事务中执行后续INSERT没有问题。
如评论所述,它似乎陷入困境的原因可能是,如果您将问题的查询序列提供给交互式解释器,它根本不会执行任何查询,因为没有任何指示任何查询的结尾。如果解释器为psql
,则此序列在查询结束时缺少分号或\g
元命令。
SQL查询本身不需要在其末尾使用分号,只有当几个查询可以一起提交时才需要。