Unlock a world of possibilities! Login now and discover the exclusive benefits awaiting you.
Buen día.
Solicito su colaboración para el siguiente inconveniente que me tiene frenado:
Estoy realizando una carga de información de diferentes archivos .xls; esta información viene un archivo mensual, pero las semanas están separadas por hojas, eso hace que haya algunos archivos con 4 hojas u otros con 5 hojas. Realicé la creación de un ciclo que me lee todos los archivos, pero no encuentro la forma para que me lea las hojas del archivo y me las cargue por semana.
Si alguien tiene una solución o algún link donde la pueda encontrar le agradezco.
Hola Juan,
Una solución podría ser usar la variable ErrorMode para evitar que el script se termine de ejecutar si encuentra un error, como podría ser el no encontrar cierta pestaña esperada dentro de un fichero.
Mira el siguiente código:
FOR EACH vsFile IN FileList('2017??.xlsx')
FOR vsSlide = 1 TO 5
IF $(vsSlide) = 5 THEN
SET ErrorMode = 0;
ENDIF
LOAD SubField(FileName(), '\', -1) AS FICHERO,
$(vsSlide) AS PESTAÑA,
COMERCIAL,
VENTAS
FROM $(vsFile) (ooxml, embedded labels, table is [$(vsSlide)]);
IF $(vsSlide) = 5 THEN
SET ErrorMode = 1;
ENDIF
NEXT
NEXT vsFile
En él se ejecutan 2 bucles FOR similares (imagino) a los que tienes en tu script: el primero recorre los ficheros con la máscara 201???.xlsx (ficheros de año y mes, p.e. 201701.xlsx) y el segundo las supuestas 5 pestañas que podría tener cada uno de los ficheros dentro de sí. Si la semana es 5 se actualiza a 0 el valor de la variable ErrorMode para que el script no aborte en caso de error ya que es posible que no encuentre una pestaña con ese número en el fichero de la iteración.
No es lo más elegante que existe pero funciona. Te adjunto un ejemplo.
Saludos,
H
Hola Juan,
Una solución podría ser usar la variable ErrorMode para evitar que el script se termine de ejecutar si encuentra un error, como podría ser el no encontrar cierta pestaña esperada dentro de un fichero.
Mira el siguiente código:
FOR EACH vsFile IN FileList('2017??.xlsx')
FOR vsSlide = 1 TO 5
IF $(vsSlide) = 5 THEN
SET ErrorMode = 0;
ENDIF
LOAD SubField(FileName(), '\', -1) AS FICHERO,
$(vsSlide) AS PESTAÑA,
COMERCIAL,
VENTAS
FROM $(vsFile) (ooxml, embedded labels, table is [$(vsSlide)]);
IF $(vsSlide) = 5 THEN
SET ErrorMode = 1;
ENDIF
NEXT
NEXT vsFile
En él se ejecutan 2 bucles FOR similares (imagino) a los que tienes en tu script: el primero recorre los ficheros con la máscara 201???.xlsx (ficheros de año y mes, p.e. 201701.xlsx) y el segundo las supuestas 5 pestañas que podría tener cada uno de los ficheros dentro de sí. Si la semana es 5 se actualiza a 0 el valor de la variable ErrorMode para que el script no aborte en caso de error ya que es posible que no encuentre una pestaña con ese número en el fichero de la iteración.
No es lo más elegante que existe pero funciona. Te adjunto un ejemplo.
Saludos,
H
Esta solución podría funcionar, el dilema es que las pestañas no están numeradas, por ejemplo, para enero están de la siguiente forma:
y así para todos los meses.
Esto me lleva a preguntarme si en la Sentencia FOR puedo colocar los nombres directos de las pestañas? O qué posible solución alterna podría tener.
Gracias.
Quedo atento.
Hola Juan,
Prueba lo siguiente ahora (cambios en naranja):
FOR EACH vsFile IN FileList('2017??.xlsx')
LET vsMesIteracion = Pick(Num(Right(SubField(SubField('$(vsFile)', '\', -1), '.', 1), 2)), 'ENERO', 'FEBRERO', 'MARZO', .., 'DICIEMBRE');
FOR vsSlide = 1 TO 5
IF $(vsSlide) = 5 THEN
SET ErrorMode = 0;
ENDIF
LET vsSlide2 = $(vsSlide) & 'ª ' & '$(vsMesIteracion)';
LOAD SubField(FileName(), '\', -1) AS FICHERO,
$(vsSlide) AS PESTAÑA,
COMERCIAL,
VENTAS
FROM $(vsFile) (ooxml, embedded labels, table is [$(vsSlide2)]);
IF $(vsSlide) = 5 THEN
SET ErrorMode = 1;
ENDIF
NEXT
NEXT vsFile
Saludos,
H
Hola Hector.
El día de ayer realice lo siguiente, no sé si es lo más optimo pero me funciono. Me gustaría conocer tus comentarios al respecto.
FOR Each vFileName in Filelist ('$(v_RutaXls)\*.xls');
LET vMes = Replace(Mid('$(vFileName)', Index('$(vFileName)',' ',-2), (Index('$(vFileName)',' ',-1)-Index('$(vFileName)',' ',-2))),' ','');
SET vLash = 'ª $(vMes)$';
FOR vSlide = 1 to 5
If $(vSlide) = 5 or $(vSlide) = 4 or $(vSlide) = 3 or $(vSlide) = 2 THEN
SET ErrorMode = 0;
ENDIF
Archivo:
LOAD SubField(FileName(), '\', -1) AS FICHERO,
'$(vSlide)$(vLash)' AS PESTAÑA,
*
FROM
[$(vFileName)]
(biff, no labels, table is [$(vSlide)$(vLash)]);
LET vNombreTablaSave = SubField('$(vFileName)','\',-1);
STORE Archivo into $(vSaveDataExt)$(vNombreTablaSave)_$(vSlide)_$(vLash).qvd (qvd);
DROP Table Archivo;
If $(vSlide) = 5 or $(vSlide) = 4 or $(vSlide) = 3 or $(vSlide) = 2 THEN
SET ErrorMode = 1;
ENDIF
NEXT
NEXT vFileName
Hola Juan,
Bajo mi punto de vista está fenomenal y seguro que tiene un muy buen rendimiento. Lo único es que yo sustituiría "IF $(vSlide) = 5 or $(vSlide) = 4 or $(vSlide) = 3 or $(vSlide) = 2 THEN" por "IF $(vSlide) > 1 THEN" por simplificarlo un poco, pero nada más.
Saludos,
H
Vale Hector, Muchas gracias!!!
Hector, quería preguntarte, este mismo código me serviría si requiero salir de la carpeta y entrar a otra? Lo pregunto por que ahora tengo varias carpetas y en cada carpeta estos archivos y el lío es que no sé si este me funcioné para lo mismo o si se puede realizar algo diferente. Por cierto, tengo que devolverme dos carpetas ya que los archivos están en CARPETA_CLIENTE\AÑO\Nombre archivo y solo voy a cargar los archivos que se encuentran el la carpeta 2017.
Agradezco mucho tu ayuda y respuesta.
Saludos.
Hola Juan,
Aquí lo que haría sería crear una subrutina que leyese los ficheros de una ruta que se le pasa como parámetro y luego se llamase a sí misma, recursivamente, para procesar las subcarpetas existentes en la carpeta actual. Un ejemplo similar lo tienes en el manual de referencia (pág 271 FOR EACH..LOOP):
// lista de todos los archivos relativos a QV en disco
SUB DoDir (Root)
FOR Each Ext in 'qvw', 'qva', 'qvo', 'qvs'
FOR Each File in filelist (Root&' \*.' &Ext)
LOAD '$(File)' as Name,
FileSize( '$(File)' ) as Size,
FileTime( '$(File)' ) as FileTime
autogenerate 1;
NEXT File
NEXT Ext
FOR Each Dir in dirlist (Root&' \*' )
call DoDir (Dir)
NEXT Dir
ENDSUB
CALL DoDir ('C:');
En tu caso si en la sentencia CALL DoDir(<Directorio>) le pasas como <Directorio> la ruta en la que tienes las carpetas de los comerciales y combinas el código anterior con este de arriba, lo tendrías hecho.
Espero que te sirva!
Saludos,
H
Gracias Hector, es muy amable. esto es perfecto para lo que necesito.
Saludos