2009-06-08 9 views
0

Il s'agit en quelque sorte d'une question générale qui a été soulevée dans plusieurs contextes, l'exemple ci-dessous est représentatif mais non exhaustif. Je suis intéressé par toutes les façons d'apprendre à travailler avec Postgres sur des sources de données imparfaites (mais assez proches).Rendre PostgreSQL un peu plus tolérant aux erreurs?

Le cas spécifique - J'utilise Postgres avec PostGIS pour travailler avec des données gouvernementales publiées dans shapefiles et xml. En utilisant le module shp2pgsql distribué avec PostGIS (par exemple sur this ensemble de données) je reçois le schéma comme celui-ci souvent:

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    | 

Je sais qu'au moins 10 de ces varchars - la fips, l'altitude, la population, etc., devrait être ints; mais en essayant de les jeter comme tels, j'ai des erreurs. En général, je pense que je pourrais résoudre la plupart de mes problèmes en permettant à Postgres d'accepter une chaîne vide comme valeur par défaut pour une colonne - disons 0 ou -1 pour un type int - en modifiant une colonne et en changeant le type. Est-ce possible? Si je crée la table avant d'importer avec les déclarations de type générées à partir de la source de données d'origine, j'obtiens de meilleurs types qu'avec shp2pgsql, et je peux itérer sur les entrées source les alimentant à la base de données. Le problème fondamental est que si j'ai 1% de mauvais champs, répartis uniformément sur 25 colonnes, je perdrai 25% de mes données car une insertion donnée échouera si un champ est mauvais. J'aimerais être capable de faire une insertion de meilleur effort et de résoudre tous les problèmes plus tard, plutôt que de perdre autant de lignes. Toute contribution provenant de personnes ayant eu à faire face à des problèmes similaires est la bienvenue - Je ne suis pas un mec MySQL qui essaye de forcer PostgreSQL à faire les mêmes erreurs que moi - traitant uniquement des données dont je n'ai pas le contrôle total plus de.

Répondre

3

Pourriez-vous produire un fichier SQL à partir de shp2pgsql et faire un massage des données avant de l'exécuter? Si les données sont au format COPY, il devrait être facile d'analyser et de changer "" en "\ N" (insérer comme nulle) pour les colonnes. Une autre possibilité serait d'utiliser shp2pgsql pour charger les données dans une table de transfert où tous les champs sont définis comme du type 'texte', puis d'utiliser une instruction INSERT ... SELECT pour copier les données vers votre emplacement final , avec la possibilité de masser les données dans le SELECT pour convertir les chaînes vierges en null, etc.

Je ne pense pas qu'il existe un moyen de contourner le comportement de la conversion des chaînes en entiers et ainsi de suite: éventuellement, vous pouvez créer votre propre type ou domaine, et définissez une distribution implicite qui était plus clémente ... mais cela semble assez désagréable, puisque les types sont vraiment juste des artefacts de la façon dont vos données arrivent dans le système et pas quelque chose que vous voulez garder après cela.

Vous avez demandé la fixation vers le haut lors de la modification du type de colonne: vous pouvez le faire aussi, par exemple:

[email protected]@[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 
[email protected]@[local] =# insert into test_table(testvalue) values('1'),('0'),(''); 
INSERT 0 3 
[email protected]@[local] =# alter table test_table alter column testvalue type int using case testvalue when '' then 0 else testvalue::int end; 
ALTER TABLE 
[email protected]@[local] =# select * from test_table; 
id | testvalue 
----+----------- 
    1 |   1 
    2 |   0 
    3 |   0 
(3 rows) 

Ce qui est presque équivalent à l'idée que je propose ci-dessus « table de mise en scène », sauf que maintenant la table de mise en scène est votre table finale. Modifier un type de colonne comme celui-ci nécessite de réécrire la table entière de toute façon: en fait, l'utilisation d'une table intermédiaire et le reformatage de plusieurs colonnes à la fois sont susceptibles d'être plus efficaces.

+0

Mes dieux, en remplaçant les chaînes vides par "\ N" fixaient practiellement toutes les erreurs. Je vais trouver comment obtenir shp2pgsql pour faire cela sur la conversion d'origine. – unmounted

+0

Cela me ramène à environ .2% taux d'erreur, en fait plus de succès avec un 'Null' non cité que '\ N'. – unmounted

Questions connexes