• Publicidad

Carga de información de Excel a base de datos

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Re: Carga de información de Excel a base de datos

Notapor Txemaracas » 2011-07-26 11:02 @501

Hola, explorer. Este es el código que tengo con lo que me pusiste pero creo que hay algo que no va bien porque me da errores. ¿Puede ser al meter las palabras en el array o en el hash? Otra cosa: ¿cómo puedo hacer para que en el caso de que si el archivo Excel en vez de .xlsx sea .xls, reconozca a los dos?


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!c:/perl/bin
  2.  
  3. use Spreadsheet::XLSX;                                 # Módulos requeridos  por el programa.
  4. use DBI;
  5. use ConectarDB;
  6. use strict;
  7. use warnings;
  8. use diagnostics;
  9. use autodie;
  10.  
  11. # Cargar excel.
  12.  
  13. my $excel = Spreadsheet::XLSX -> new ('test.xlsx');    
  14.  
  15. my($dbh,$sth);
  16.  
  17. $dbh = ConectarDB->connect();
  18.  
  19. $sth = $dbh->prepare("SELECT * FROM hoja1");
  20.  
  21. $sth->execute();
  22.  
  23. my @base_de_datos;
  24.  
  25.   while (my $ref = $sth->fetchrow_hashref()) {
  26.  
  27.     @base_de_datos = $ref->{'palabra'};
  28.    
  29.   }
  30.  
  31. $sth->finish();
  32.  
  33. $dbh->disconnect();
  34.  
  35. my %excel;
  36.  
  37. foreach my $sheet (@{$excel -> {Worksheet}}) {                                              
  38.         printf("Sheet: %s\n", $sheet->{Name});                                            
  39.  
  40.         my$hoja = $sheet->{Name};                                                          
  41.  
  42.         $sheet -> {MaxRow} ||= $sheet -> {MinRow};
  43.  
  44.          foreach my $row ($sheet -> {MinRow} .. $sheet -> {MaxRow}) {                      
  45.                 $sheet -> {MaxCol} ||= $sheet -> {MinCol};
  46.  
  47.                 foreach my $col ($sheet -> {MinCol} ..  $sheet -> {MaxCol}) {              
  48.  
  49.                         my $cell = $sheet -> {Cells} [$row] [$col];                        
  50.  
  51.                         if (exists $cell->{Val}and $cell->{Val} =~ m/h/i) {              
  52.  
  53.                                 $excel = $cell->{'palabra'};
  54.  
  55.                         }
  56.                        
  57.                 }
  58.          }
  59.  
  60.  
  61.  }
  62.  
  63.  
  64.  
  65. ## Recorremos la base de datos
  66. my @palabras_borradas;                                  # aquí guardaremos las palabras a eliminar
  67.  
  68. for my $registro (@base_de_datos) {
  69.  
  70.     if (exists $excel{ $registro->{'palabra'} }) {        # si existe la palabra en el Excel...
  71.         delete $excel{ $registro->{'palabra'} };          # así que la borramos (ya la teníamos)
  72.     }
  73.     else {                                              # no existe: el usuario la ha borrado
  74.         push @palabras_borradas, $registro->{'palabra'};
  75.     }
  76. }
  77.  
  78. # en %excel quedarán las palabras nuevas que hay que meter en la base de datos
  79. print "Nuevos palabras a meter: ", join('/', keys %excel), "\n";
  80.  
  81. # y en @palabras_borradas, las que hay que quitar de la base de datos
  82. print "Palabras a borrar: ", join('/', @palabras_borradas), "\n";
Coloreado en 0.009 segundos, usando GeSHi 1.0.8.4
Txemaracas
Perlero nuevo
Perlero nuevo
 
Mensajes: 136
Registrado: 2011-04-04 10:06 @462

Publicidad

Re: Carga de información de Excel a base de datos

Notapor explorer » 2011-07-26 11:52 @536

Pues sí, el programa está a medias, en cuanto a lo de crear las estructuras de datos.

Recuerda que puedes usar Data::Dumper para ver el contenido de las variables, y así sabrás si lo estás construyendo bien o mal.

Como ya he dicho en el mensaje anterior, las estructuras que he creado para el ejemplo, son solo una forma de las varias que hay para guardar la información.

Analizando tu código, llego a las siguientes conclusiones:
* de la base de datos solo te interesa guardar las palabras, y nada más.
* de la hoja Excel, haces un recorrido por todas las hojas, por todas las filas y por todas las columnas, y si en la celda hay una 'h' mayúscula o minúscula, la intentas guardar en %excel (digo 'intentas', porque no lo haces).

Entonces, queda claro que no estamos hablando de estructuras de datos, sino solo de listas de palabras, con lo que se puede simplificar el código mucho más. (No probado.)

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!c:/perl/bin
  2.  
  3. use strict;
  4. use warnings;
  5. use diagnostics;
  6. use autodie;
  7.  
  8. use DBI;
  9. use ConectarDB;
  10. use Spreadsheet::XLSX;                                 # Módulos requeridos  por el programa.
  11.  
  12. # Cargar Base de datos
  13. my $dbh = ConectarDB->connect();
  14. my $sth = $dbh->prepare("SELECT * FROM hoja1");
  15.  
  16. $sth->execute();
  17.  
  18. my %palabras_en_base_de_datos;
  19.  
  20. while (my $ref = $sth->fetchrow_hashref()) {
  21.     $palabras_en_base_de_datos{$ref->{'palabra'}} = 1;    # Apuntamos la palabra en nuestro diccionario
  22. }
  23.  
  24. $sth->finish();
  25. $dbh->disconnect();
  26.  
  27. # Cargar Excel
  28. my $excel = Spreadsheet::XLSX -> new ('test.xlsx');
  29.  
  30. my %palabras_en_excel;
  31.  
  32. foreach my $sheet (@{$excel -> {Worksheet}}) {                                              
  33.     printf("Sheet: %s\n", $sheet->{Name});
  34.  
  35.     my $hoja = $sheet->{Name};
  36.  
  37.     $sheet -> {MaxRow} ||= $sheet -> {MinRow};
  38.  
  39.     foreach my $row ($sheet -> {MinRow} .. $sheet -> {MaxRow}) {
  40.         $sheet -> {MaxCol} ||= $sheet -> {MinCol};
  41.  
  42.         foreach my $col ($sheet -> {MinCol} ..  $sheet -> {MaxCol}) {
  43.             my $cell = $sheet -> {Cells} [$row] [$col];
  44.             my $val  = $cell->{Val} // '';              # El operando '//' es de Perl v5.10
  45.  
  46.             if ($val =~ m/h/i) {                        # Si tiene al menos una hache...
  47.                 $palabras_en_excel{$val} = 1;           # Anotamos la existencia en otro diccionario
  48.             }
  49.         }
  50.     }
  51. }
  52.  
  53.  
  54. ## Recorremos la base de datos
  55. my @palabras_borradas;                                  # aquí guardaremos las palabras a eliminar
  56.  
  57. for my $palabra (keys %palabras_en_base_de_datos) {
  58.  
  59.     if (exists $palabras_en_excel{$palabra}) {                  # Si también existe la palabra en el Excel...
  60.         delete $palabras_en_excel{$palabra};                    # la quitamos
  61.     }
  62.     else {                                              # no existe: el usuario la ha borrado
  63.         push @palabras_borradas, $palabra;                      # la guardamos para luego
  64.     }
  65. }
  66.  
  67. # En %palabras_en_excel quedarán las palabras nuevas que hay que meter en la base de datos
  68. print "Nuevos palabras a meter: ", join('/', keys %palabras_en_excel), "\n";
  69.  
  70. # Y en @palabras_borradas, las que hay que quitar de la base de datos
  71. print "Palabras a borrar: ", join('/', @palabras_borradas), "\n";
  72.  
  73. __END__
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Carga de información de Excel a base de datos

Notapor Txemaracas » 2011-07-26 16:23 @724

Vale voy a probarlo. No me has contestado a lo de si se puede hacer algo para que el programa reconozca si es .xlsx o .xls
Txemaracas
Perlero nuevo
Perlero nuevo
 
Mensajes: 136
Registrado: 2011-04-04 10:06 @462

Re: Carga de información de Excel a base de datos

Notapor explorer » 2011-07-26 16:32 @730

Yo para leer archivos Excel uso Spreadsheet::Read, que se encarga por sí mismo de adivinar el formato (de entre 6), por lo que no tendré que cambiar el programa cuando el cliente se aburra de comprar licencias de Office de Micro$oft.

Si no lo quieres usar, tendrás que hacer un if() para saber qué extensión tiene, y entonces elegir la creación de un objeto Spreadsheet::XLSX o de un objeto Spreadsheet::ParseExcel, aunque... ahora mismo no sé si ambos objetos contienen los mismos métodos para acceder a las contenidos de las celdas.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Carga de información de Excel a base de datos

Notapor Txemaracas » 2011-07-26 17:17 @761

Vale, entonces si quiero usar el Spreadsheet::Read tendría que modificar el código porque no es el mismo que utiliza el ::XLSX, ¿no?
Txemaracas
Perlero nuevo
Perlero nuevo
 
Mensajes: 136
Registrado: 2011-04-04 10:06 @462

Re: Carga de información de Excel a base de datos

Notapor explorer » 2011-07-26 17:27 @768

Sí.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Carga de información de Excel a base de datos

Notapor Txemaracas » 2011-08-11 07:34 @357

Hola. He estado mirando el documento de Spreadsheet::Read para crear un nuevo código pero tengo algunas dudas de si lo hago bien o no.

Código:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!c:/perl/bin
  2.  
  3. use Spreadsheet::Read;
  4. use autodie;
  5. use Modern::Perl;
  6. use Data::Dumper;
  7.  
  8. my $BASE = ReadData( 'test.xls', cells => 0, attr => 1 );
  9.  
  10. die "ERROR: Base de datos no encontrada" if not $BASE;
  11.  
  12. my %HOJAS = %{ $BASE->[0]->{sheet} };  # Relación hojas -> índices
  13.  
  14. foreach my $sheet ( 1 .. $BASE->[0]{sheets} ) {
  15.  
  16.     printf( "Sheet: %s\n", $sheet->{Label} );
  17.  
  18.     my $HOJA
  19.         = $BASE->[ $HOJAS{$sector} ]->{cell};   # Referencia a la hoja $sector
  20.  
  21.     my $maximo_filas = $BASE->[ $HOJAS{$sector} ]->{maxrow};
  22.     my $maximo_cols  = $BASE->[ $HOJAS{$sector} ]->{maxcol};
  23.     my $fila         = 1;
  24.     my $encontrado   = 0;
  25.  
  26.     while ( $fila <= $maximo_filas and $encontrado == 0 ) {
  27.  
  28.         my $columna = 1;
  29.  
  30.         while ( $columna <= $maximo_cols and $encontrado == 0 ) {
  31.  
  32.             my $cell = $HOJA->[$columna]->[$fila];
  33.  
  34.             if ( exists $cell->{Val} and $cell->{Val} =~ m/h/i ) {
  35.  
  36.                 encontrado = 1;
  37.                 ) else {
  38.  
  39.                         $columna++;
  40.                 }
  41.             }
  42.             if ( encontrado == 0 ) {
  43.  
  44.                     $fila++;
  45.             }
  46.  
  47.         }
  48.  
  49.         for ( $HOJA->[$columna]->[$fila] ) {
  50.  
  51.                 # Hacer algo con el contenido de la celda $HOJA->[$columna]->[$fila]
  52.                 printf( " Palabra en Castellano:  %s    ",
  53.                     $HOJA->[ --$columna ]->[$fila] );
  54.                 printf( " Palabra en Ingles:  %s\n",
  55.                     $HOJA->[$columna]->[$fila] );
  56.  
  57.                 $fila++;
  58.  
  59.         }
  60.  
  61.     }
  62.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


La duda que tengo, aparte de si el código está bien escrito, es:

¿Cómo hago para saber si el archivo que tengo en la carpeta es .xls o .xlsx?

Lo que estoy intentando hacer con este código es :

1) Recorrer cada hoja con el foreach() de la línea 15 e imprimir el nombre de la hoja.

2) Recorrer cada una de las hojas con dos whiles(): el primero para las filas y otro para las columnas y en el momento que encuentre una palabra que empiece por "h" habré encontrado la columna que buscaba y saldré de los bucles.

3) Con el valor de la fila y columna del bucle anterior hacer un for() de la línea 49 para mostrar por pantalla todas las palabras tanto en inglés como su significado en castellano que está en la columna anterior a la palabra en inglés.
Txemaracas
Perlero nuevo
Perlero nuevo
 
Mensajes: 136
Registrado: 2011-04-04 10:06 @462

Re: Carga de información de Excel a base de datos

Notapor explorer » 2011-08-11 13:10 @590

El código no está bien...

Es mejor extraer antes de hacer los bucles, los valores máximos de las filas y columnas, de cada hoja.

Así, lo mejor es obtener los datos (de forma esquemática):

$sheets = $BASE->[0]->{sheets} guarda el número de hojas

# Bucle por todas las hojas $hoja (1.. $sheets)
$maxrom = $BASE->[$hoja]->{maxrow} # número máximo de filas que hay en la hoja
$maxcol = $BASE->[$hoja]->{maxcol} # número máximo de columnas que hay en la hoja

# Bucle por cada hoja
BUCLE:
# Recorremos por cada fila, de 1 a $maxrow
# Recorremos por cada columna, de 1 a $maxcol
$BASE->[$hoja]->{cell}->[$columna]->[$fila] # accedemos a la celda correspondiente

Si la celda contiene un 'h', guardamos el valor de fila y columna en variables globales, y
hacemos un last BUCLE; para que salga de los dos bucles internos

# Fin de bucles

# Si tenemos coordenadas de la celda, seguimos...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Carga de información de Excel a base de datos

Notapor Txemaracas » 2011-08-12 06:39 @319

Vale he modificado en base a lo que me has dicho pero, por ejemplo, nunca he utilizado "last BUCLE;" y no sé si está bien puesto.

Pero me da un error en el el bucle de la línea 39 me dice que "$col_enc necesita un paquete especifico".

Y la otra duda que no sé si te puse en el anterior es que si con esto me sirve para diferenciar entre .xls y .xlsx.


CÓDIGO:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!c:/perl/bin
  2.  
  3. use Spreadsheet::Read;                                 # Módulos requeridos  por el programa.
  4. use autodie;
  5. use Modern::Perl;
  6. use Data::Dumper;
  7.  
  8.  
  9.     my $BASE = ReadData('test.xls', cells => 0, attr => 1);
  10.  
  11.     die "ERROR: Base de datos no encontrada" if not $BASE;
  12.      
  13.     my %HOJAS = %{$BASE->[0]->{sheet}};             # Relación hojas -> índices
  14.      
  15.     my $sheets = $BASE->[0]->{sheets};              #Numero de hojas.
  16.    
  17.     foreach my $hoja (1..$sheets){
  18.        
  19.          printf("Sheet: %s\n", $BASE->[$hoja]->{Label});
  20.          
  21.          my $maxrow = $BASE->[$hoja]->{maxrow}; # número máximo de filas que hay en la hoja
  22.          my $maxcol = $BASE->[$hoja]->{maxcol}; # número máximo de columnas que hay en la hoja
  23.        
  24.          foreach my $fila (1..$maxrow){
  25.            
  26.             foreach my $columna (1..$maxcol){
  27.                
  28.                 my $cell = $BASE->[$hoja]->{cell}->[$columna]->[$fila]; # accedemos a la celda correspondiente
  29.                
  30.                 if (exists $cell->{Val}and $cell->{Val} =~ m/h/i) {    #Mirar si tiene valor la celda  y en caso de que tenga siel contenido empiezapor "h".
  31.                    
  32.                     my $fila_enc = $fila;
  33.                     my $col_enc = $columna;
  34.                     last BUCLE;
  35.                 }
  36.             }
  37.          }
  38.        
  39.          foreach my $col($col_enc..$maxcol) {
  40.         # Hacer algo con el contenido de la celda $HOJA->[$columna]->[$fila]
  41.               printf(" Palabra en Castellano:  %s    ",$BASE->[$hoja]->{cell}->[--$col]->[$fila]);
  42.               printf(" Palabra en Ingles:  %s\n",$BASE->[$hoja]->{cell}->[$col]->[$fila]);
  43.                    
  44.          }
  45.  
  46.     }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
Txemaracas
Perlero nuevo
Perlero nuevo
 
Mensajes: 136
Registrado: 2011-04-04 10:06 @462

Re: Carga de información de Excel a base de datos

Notapor explorer » 2011-08-12 07:45 @364

Usando Spreadsheet::Read no necesitas saber si la extensión es xls o xlsx. El módulo se encargará de leerlo cargando el módulo correcto.

De todas maneras, si necesitas saber qué extensión tiene el fichero, te vale con extraerlo y hacer una comparación:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use Modern::Perl;
  2. my $nombre_fichero = 'test.xls';
  3. my($extension) = $nombre_fichero =~ m/\.(\w+)$/;
  4. given ($extension) {
  5.     when ('xls') {
  6.         say "Es un fichero xls";
  7.     }
  8.     when ('xlsx') {
  9.         say "Es un fichero xlsx";
  10.     }
  11. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


En el código hay varios problemas:
  • La línea 13 sobra, porque no estás usando la variable %HOJAS en ningún otro sitio.
  • En la línea 23 es donde tienes que poner la etiqueta para el last:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using perl Syntax Highlighting
    1.          BUCLE:
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
  • La expresión regular de la línea 30 está mal, porque no hace lo que dice el comentario que le sigue, que dice que esperamos encontrar que el contenido de la celda *comience* por 'h'. La expresión regular correcta será: m/^h/i
  • Hay otro problema en la línea 30. Las celdas creadas por Spreadsheet::Read no contienen un hash con una clave 'Val', sino que contienen el propio valor de la celda. La línea 30 habría que escribirla así:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using perl Syntax Highlighting
    1.                 if (defined $cell and $cell =~ m/^h/i) {    # Mirar si la celda empieza por "h"
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
  • Las líneas 32 y 33 también están mal: estás declarando variables locales (con my()) al contexto de llaves de las líneas 30 a 35. Eso quiere decir que esas variables serán desconocidas fuera de esas líneas. Lo que tienes que hacer es declarar antes de los bucles:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using perl Syntax Highlighting
    1.          my($fila_enc, $col_enc);
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
    y ahora sí que puedes hacer uso de ellas:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using perl Syntax Highlighting
    1.                     $fila_enc = $fila;
    2.                     $col_enc  = $columna;
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
  • Aún no me queda clara la forma en la que quieres sacar las traducciones. Dices que, una vez localizada la columna, las distintas traducciones están en el resto de columnas. Hay entonces un error en la forma de presentar los datos, creo yo. En la línea 41 estás predecrementando la variable $col, lo cual es siempre algo problemático hacerlo dentro de un bucle en que la variable de control es esa misma variable. Yo lo que creo que quieres hacer es:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using perl Syntax Highlighting
    1.         if ($fila_enc and $col_enc) {
    2.             print " Palabra en Castellano:  ", $BASE->[$hoja]->{cell}->[$col_enc]->[$fila_enc], ":\n";
    3.             for my $col ($col_enc+1 .. $maxcol) {
    4.                 my $celda = $BASE->[$hoja]->{cell}->[$col]->[$fila_enc];
    5.                 if (defined $celda) {
    6.                     printf "\t%s\n", $celda;
    7.                 }
    8.             }
    9.         }
    10.         else {
    11.             print "No hay traducción\n";
    12.         }
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
    es decir, pintamos la palabra en castellano que hemos encontrado en esas coordenadas (en el caso de haberlo encontrado), y recorremos las columnas siguientes con las traducciones.
Naturalmente, no lo he probado, así que no sé si estará todo bien o se me ha escapado algo más. Ya nos contarás.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

AnteriorSiguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados

cron