coc*_*nup 3 postgresql transactions insert alter
我的用例如下:我正在定期将数据导入到 PostgreSQL 数据库,其中必须定期导入一些外部数据。
需要注意的是,数据的结构可能会从一个导入更改为另一个导入,因此在插入新数据之前,我会在每次导入时截断+删除所有列。
我想将整个操作包装在单个事务中,因此,如果出现问题,事务将回滚,并且旧数据仍然可以访问(两害相权取其轻)。
例如,数据导入语句可能如下所示:
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
Run Code Online (Sandbox Code Playgroud)
目前这不起作用。INSERT 语句会被卡住,因为在调用它时,该表仍然被前面的 ALTER TABLE 语句锁定。
有什么方法可以在 Postgres 事务中实现这一点,还是我应该放弃并寻求其他应用程序端解决方案?
目前这不起作用。INSERT 语句会被卡住,因为在调用它时,该表仍然被前面的 ALTER TABLE 语句锁定。
不,事务不能以这种方式锁定自身。如果 INSERT 是由另一个事务发起的,而不是由已经对该对象具有强锁的事务发起的,则该 INSERT 将被阻止。删除该列并在同一事务中执行后续 INSERT 没有问题。
正如评论中提到的,它似乎被卡住的原因可能是,如果将问题中的查询序列提供给交互式解释器,它根本不会执行任何查询,因为没有结束的指示任何查询。如果解释器是此序列,则查询末尾psql缺少分号或元命令。\g
SQL 查询本身不需要在末尾加分号,只有当多个查询可以一起提交时才需要分号。
您可以在http://rextester.com/OTU89086中查看示例
您可以添加的列数是有限制的(即使您删除其他列)。如果你做了很多你会得到:
54011: tables can have at most 1600 columns
Run Code Online (Sandbox Code Playgroud)
你可以在这里看到这个问题:
--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;
Run Code Online (Sandbox Code Playgroud)
在这里尝试一下: http: //rextester.com/RPER86062
| 归档时间: |
|
| 查看次数: |
8361 次 |
| 最近记录: |