INSERT en Perl
Insertar datos en MySQL desde Perl es una tarea habitual que se resuelve de forma elegante con DBI y sus sentencias preparadas. Los placeholders protegen contra inyecciones SQL, y los métodos de ejecución por lotes permiten insertar grandes volúmenes de datos de forma eficiente. En este artículo aprenderás las diferentes técnicas de inserción disponibles en Perl.
Requisitos previos
Necesitas una conexión DBI configurada y la tabla productos creada. Si no la tienes, consulta los artículos anteriores.
Código completo
Este ejemplo inserta un producto y muestra el ID generado:
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
my $dbh = DBI->connect(
"DBI:mysql:database=tienda;host=localhost",
"root", "tu_contraseña",
{ RaiseError => 1, AutoCommit => 1, mysql_enable_utf8mb4 => 1 }
);
my $sth = $dbh->prepare(
"INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)"
);
$sth->execute('Tablet Samsung Galaxy Tab S9', 'Tablets', 8999.00, 35);
my $nuevo_id = $dbh->{mysql_insertid};
print "Producto insertado exitosamente\n";
print "ID generado: $nuevo_id\n";
print "Filas afectadas: ", $sth->rows(), "\n";
$sth->finish();
$dbh->disconnect();Salida esperada:
Producto insertado exitosamente
ID generado: 9
Filas afectadas: 1
Explicación paso a paso
El flujo de inserción en DBI sigue el patrón prepare-execute. Primero preparas la sentencia con placeholders ?, luego la ejecutas pasando los valores como argumentos. DBI se encarga de escapar y formatear cada valor según su tipo.
La propiedad $dbh->{mysql_insertid} devuelve el último ID AUTO_INCREMENT generado, equivalente a LAST_INSERT_ID() en SQL. El método $sth->rows() devuelve el número de filas afectadas por la operación.
Insertar con variables
my $nombre = 'Cargador USB-C 65W';
my $categoria = 'Accesorios';
my $precio = 599.00;
my $stock = 300;
my $sth = $dbh->prepare(
"INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)"
);
$sth->execute($nombre, $categoria, $precio, $stock);
print "Producto '$nombre' creado con ID: $dbh->{mysql_insertid}\n";
$sth->finish();Insertar usando do() para sentencias simples
Para inserciones de una sola vez, puedes usar do() como atajo:
my $filas = $dbh->do(
"INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)",
undef,
'Hub USB-C 7 en 1', 'Accesorios', 899.00, 150
);
print "Filas insertadas: $filas\n";
print "ID: $dbh->{mysql_insertid}\n";El segundo argumento undef corresponde a los atributos del statement handle, que normalmente no se necesitan.
Inserción masiva
Cuando necesitas insertar muchos registros, reutilizar la sentencia preparada es mucho más eficiente que preparar una nueva para cada fila:
my @productos = (
['Impresora HP LaserJet', 'Impresoras', 3499.00, 20],
['Cable HDMI 2.1 3m', 'Accesorios', 349.00, 500],
['Mousepad XXL Gaming', 'Accesorios', 449.00, 200],
['Soporte Monitor Ajustable', 'Accesorios', 1299.00, 75],
['Adaptador DisplayPort', 'Accesorios', 249.00, 400],
);
my $sth = $dbh->prepare(
"INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)"
);
my $insertados = 0;
$dbh->begin_work();
eval {
for my $producto (@productos) {
$sth->execute(@$producto);
$insertados++;
}
$dbh->commit();
};
if ($@) {
$dbh->rollback();
print "Error: $@\n";
} else {
print "Registros insertados: $insertados\n";
}
$sth->finish();Salida esperada:
Registros insertados: 5
Inserción masiva con execute_array
DBI ofrece execute_array() para ejecutar una sentencia preparada con múltiples conjuntos de parámetros de forma optimizada:
my @nombres = ('Webcam HD', 'Micrófono USB', 'Anillo de Luz LED');
my @categorias = ('Periféricos', 'Audio', 'Accesorios');
my @precios = (799.00, 1299.00, 449.00);
my @stocks = (100, 80, 150);
my $sth = $dbh->prepare(
"INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)"
);
my $tuples = $sth->execute_array(
{ ArrayTupleStatus => \my @estado },
\@nombres, \@categorias, \@precios, \@stocks
);
print "Registros insertados: $tuples\n";
$sth->finish();Caso práctico
Veamos un script que importa productos desde un archivo CSV:
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Text::CSV;
my $dbh = DBI->connect(
"DBI:mysql:database=tienda;host=localhost",
"root", "tu_contraseña",
{ RaiseError => 1, AutoCommit => 0, mysql_enable_utf8mb4 => 1 }
);
my $csv = Text::CSV->new({ binary => 1, auto_diag => 1 });
my $sth = $dbh->prepare(
"INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)"
);
my $insertados = 0;
my $errores = 0;
eval {
open my $fh, "<:encoding(utf8)", "productos.csv" or die "No se puede abrir: $!";
$csv->header($fh); # Saltar encabezados
while (my $fila = $csv->getline_hr($fh)) {
eval {
$sth->execute(
$fila->{nombre}, $fila->{categoria},
$fila->{precio}, $fila->{stock}
);
$insertados++;
};
if ($@) {
$errores++;
warn "Error en línea: $@";
}
}
close $fh;
$dbh->commit();
};
if ($@) {
$dbh->rollback();
print "Error fatal: $@\n";
}
print "Importación completada: $insertados insertados, $errores errores\n";
$sth->finish();
$dbh->disconnect();Manejo de errores
Los errores comunes al insertar datos:
sub insertar_seguro {
my ($dbh, $nombre, $categoria, $precio, $stock) = @_;
eval {
$dbh->do(
"INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)",
undef, $nombre, $categoria, $precio, $stock
);
};
if ($@) {
my $error = $@;
if ($error =~ /Duplicate entry/) {
return { exito => 0, mensaje => "Ya existe un producto con ese nombre" };
} elsif ($error =~ /cannot be null/) {
return { exito => 0, mensaje => "Faltan campos obligatorios" };
} elsif ($error =~ /Data too long/) {
return { exito => 0, mensaje => "Uno de los valores excede la longitud permitida" };
} elsif ($error =~ /foreign key constraint/) {
return { exito => 0, mensaje => "Referencia a tabla externa no válida" };
} else {
return { exito => 0, mensaje => "Error: $error" };
}
}
return { exito => 1, id => $dbh->{mysql_insertid} };
}Ahora que sabes cómo insertar datos, en el siguiente artículo aprenderás a ejecutar consultas SELECT en MySQL desde Perl.
Escrito por Eduardo Lázaro
