使PostgreSQL更容错?

时间:2009-06-08 23:04:19

标签: sql postgresql types postgis

这是一个在几种情况下出现的一般性问题,下面的例子具有代表性,但并非详尽无遗。我对任何学习使用Postgres的不完美(但足够接近)数据源的方式感兴趣。

具体案例 - 我正在使用Postgres和PostGIS来处理在shapefile和xml中发布的政府数据。使用随PostGIS一起发布的shp2pgsql模块(例如在this数据集上)我经常得到这样的模式:

   Column   |         Type          | 
------------+-----------------------+-
 gid        | integer               |
 st_fips    | character varying(7)  | 
 sfips      | character varying(5)  | 
 county_fip | character varying(12) | 
 cfips      | character varying(6)  | 
 pl_fips    | character varying(7)  | 
 id         | character varying(7)  | 
 elevation  | character varying(11) | 
 pop_1990   | integer               | 
 population | character varying(12) | 
 name       | character varying(32) | 
 st         | character varying(12) | 
 state      | character varying(16) | 
 warngenlev | character varying(13) | 
 warngentyp | character varying(13) | 
 watch_warn | character varying(14) | 
 zwatch_war | bigint                | 
 prog_disc  | bigint                | 
 zprog_disc | bigint                | 
 comboflag  | bigint                | 
 land_water | character varying(13) | 
 recnum     | integer               | 
 lon        | numeric               | 
 lat        | numeric               | 
 the_geom   | geometry              |

我知道这些变种中至少有10种 - 鱼腥草,海拔,种群等应该是整体的;但是当我试图将它们投射时,我会得到错误。总的来说,我认为我可以通过允许Postgres接受空字符串作为列的默认值来解决我的大多数问题 - 比如说int类型为0或-1 - 当更改列并更改类型时。这可能吗?

如果我在使用从原始数据源生成的类型声明导入之前创建表,我会获得比使用shp2pgsql更好的类型,并且可以迭代将它们提供给数据库的源条目,丢弃任何失败的插入。根本问题是,如果我有1%的坏字段,均匀分布在25列以上,我将丢失25%的数据,因为如果任何字段不好,给定的插入将失败。我希望能够做出尽力而为的插入并在以后修复任何问题,而不是丢失那么多行。

来自处理类似问题的人的任何意见都是受欢迎的 - 我不是一个试图打击PostgreSQL以犯下我习惯的所有相同错误的MySQL人 - 只处理我无法完全控制的数据

1 个答案:

答案 0 :(得分:3)

你能从shp2pgsql生成一个SQL文件,并在执行之前对数据进行一些按摩吗?如果数据是COPY格式,则应该很容易解析并将“”更改为“\ N”(插入为空)列。

另一种可能性是使用shp2pgsql将数据加载到临时表中,其中所有字段都定义为“文本”类型,然后使用INSERT ... SELECT语句将数据复制到最终位置,有可能按下SELECT中的数据,将空字符串转换为null等。

我认为没有办法覆盖字符串转换为整数的行为等等:可能你可以创建自己的类型或域,并定义一个更宽松的隐式转换......但是这个听起来很讨厌,因为这些类型实际上只是你的数据如何到达系统的工件,而不是你想要保留的东西。

您在更改列类型时询问了如何修复它:您也可以这样做,例如:

steve@steve@[local] =# create table test_table(id serial primary key, testvalue text not null);
NOTICE:  CREATE TABLE will create implicit sequence "test_table_id_seq" for serial column "test_table.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "test_table_pkey" for table "test_table"
CREATE TABLE
steve@steve@[local] =# insert into test_table(testvalue) values('1'),('0'),('');
INSERT 0 3
steve@steve@[local] =# alter table test_table alter column testvalue type int using case testvalue when '' then 0 else testvalue::int end;
ALTER TABLE
steve@steve@[local] =# select * from test_table;
 id | testvalue
----+-----------
  1 |         1
  2 |         0
  3 |         0
(3 rows)

这几乎相当于我上面建议的“临时表”的想法,除了现在登台表 是你的最终表。改变这样的列类型需要重写整个表:所以实际上,使用登台表并一次重新格式化多个列可能会更有效。