2010-05-18 7 views
5

Tengo un script de Perl que inserta datos en Postgres de acuerdo con un archivo de texto delimitado por tuberías. A veces, un campo es nulo (como se esperaba). Sin embargo, Perl convierte este campo en una cadena vacía y falla la instrucción de inserción de Postgres.¿Cómo inserto campos nulos con DBD :: Pg de Perl?

He aquí un fragmento de código:


use DBI; 

#Connect to the database. 
$dbh=DBI->connect('dbi:Pg:dbname=mydb','mydb','mydb',{AutoCommit=>1,RaiseError=>1,PrintError=>1}); 

#Prepare an insert. 
$sth=$dbh->prepare("INSERT INTO mytable (field0,field1) SELECT ?,?"); 

while (<>){ 
    #Remove the whitespace 
    chomp; 

    #Parse the fields. 
    @field=split(/\|/,$_); 

    print "$_\n"; 

    #Do the insert. 
    $sth->execute($field[0],$field[1]); 
} 

Y si la entrada es:

 
a|1 
b| 
c|3 

EDIT: Utilice esta entrada en su lugar.

 
a|1|x 
b||x 
c|3|x 

Fallará en b|.

DBD::Pg::st execute failed: ERROR: invalid input syntax for integer: ""

Solo quiero que inserte un nulo en el campo1 en su lugar. ¿Algunas ideas?

EDITAR: simplifiqué la entrada en el último minuto. La entrada anterior realmente lo hizo funcionar por alguna razón. Así que ahora cambié la entrada a algo que hará que el programa falle. También tenga en cuenta que field1 es un tipo de datos enteros anulables.

+0

Este código funciona aquí, Perl 5.10.1, 2.15.1 DBD :: Pg , Postgres 8.4. Además, ¿por qué estás usando SELECT? en lugar de VALUES (?,?)? – MkV

+0

Además, use strict; usa advertencias; y arregle sus declaraciones de variables – MkV

+0

Acerca del formato SQL ... el código real en realidad tiene algunas combinaciones en esa selección. – User1

Respuesta

4

no estoy seguro de que, si la prueba de su código pegado y datos en conjunto, trabajan con Perl 5.10.1, 2.15.1 DBD :: Pg y PostgreSQL 8.4. También debe usar estrictas y advertencias y no confiar en el alcance del paquete para sus variables.

Si cambia su código y datos para usar tres o más campos, dejando uno no terminal vacío, entonces puede desencadenar el error de DBD :: Pg. Añadir una línea como esta a su código antes de ejecutar la instrucción preparada:

map { $_ eq '' and $_ = undef } @field; 

Para asignar cadenas vacías en @field a UNDEF

+0

Eso se encargó de convertir las cadenas vacías en nulos. Es extraño que la eliminación de un campo en la entrada provoque que la cadena vacía se vuelva nula (al menos, lo que parece haber sucedido). – User1

+0

foreach sería mucho más legible aquí –

+0

Si una cadena termina en los caracteres que está dividiendo, como 'a | 4 |' luego, el elemento de la matriz final no se rellena en absoluto, no se convierte en una cadena vacía, por lo que es undef, consulte perldoc -f split. – MkV

0

undef normalmente se asigna a NULL. Parece que estás insertando la cadena vacía, que no es lo mismo que undef.

+0

has probado el código? Con solo dos campos? – MkV

2

El paquete DBI asigna undef a NULL. (-Dad definida de Perl frente a la lógica falsedad es en realidad una muy buena opción para la lógica ternaria de SQL.)

Así, en su bucle while, simplemente comprobar si el campo indicado es una cadena vacía, y si es así, lo convierten en undef en su lugar:

while (<>){ 
    ... 
    #Parse the fields. 
    @field=split(/\|/,$_); 

    if ($field[1] eq '') { 
     # handle NULLs 
     $field[1] = undef; 
    } 

    #Do the insert. 
    $sth->execute($field[0],$field[1]); 
} 
+0

su if nunca es verdadero, y si usa use strict; usa advertencias; en su código obtiene 'Uso del valor $ uninitialized field' [1] en la cadena eq ' – MkV

+1

@james, no estoy seguro de a qué se refiere. Funciona bien con 'strict' y' warnings' habilitados y el condicional tiene éxito.'perl -Mstrict -Mwarnings -MData :: Dumper -le 'my $ str =" a | b || d "; mi @a = split/\ | /, $ str; if ($ a [2] eq "") {$ a [2] = undef; }; print Dumper \ @ a'' – friedo

+0

Funciona ahora, pero como la pregunta se planteó originalmente (y cuando la respondiste), solo había dos campos y el campo vacío estaba al final, devolviendo undef para ese índice. – MkV

Cuestiones relacionadas