martes, 29 de junio de 2010

Formato de Celdas en EXCEL - tipo Numero - No Numero cientifico

Cuando se crean archivos excel desde paginas, siempre tengo problemas con los formatos de las celdas, por lo que he investigado y he podido encontrar una solucion aceptable.

cuando en las celda del excel (tabla html) que se va a exportar son numeros, por ejemplo:
<td>502682196768</td>

el resultado en excel de esto será

5,02682E+11

pero si le agregamos un estilo que interpreta excel nos mostrara como numero normal
es decir:

<td style='mso-number-format:0;'>502682196768</td>

502682196768

entonces la clave del formato esta en agregar lo siguiente a la celda.

style='mso-number-format:0;'


espero ayudar a muchos que tienen el mismo problema.

yo he navegado por muchos sitios y la mejor opcion que habia encontrado era agregar un espacio al numero para que éste no sea convertido a numero cientifico, pero esta solucion tenia como problema que los valores no se podia sumar o aplicar una formula sobre este.
ahora con la solucion que propongo si es posible agregar una formula de agregacion y que el resultado sea tambien un numero no cientifico.

TAN TAN.

martes, 23 de marzo de 2010

Leer Campo XML en SQL Server

Como podemos leer campo XML y filtrar por campos que estan dentro del XML

tenemos esta tabla




como ejemplo tenemos el siguiente XML:




para leer el campo XML de la tabla TabXML , en el campo XMLData, se hace de la siguiente forma

SELECT
ID,
D.C.value('@Nombre', 'Varchar(30)') as Nombre,
D.C.value('@Apellido', 'Varchar(30)') as Apellido,
D.C.value('@telefono', 'Varchar(10)') as Telefono,
D.C.value('@Email', 'Varchar(100)') as Email
FROM TabXML
CROSS APPLY XMLData.nodes('ROOT/VALORES') D(c) -- recuerda que XMLData es el nombre del campo donde esta el XML
WHERE D.c.value('@Nombre', 'varchar(30)') = 'Sergio'

este query mostrara el resultado , todas los registros en donde el nombre sea igual a 'Sergio'

ID Nombre Apellido Fono Email
1 Sergio Valenzuela 555444 Sergio.Valenzuela@engendro.cl
1 Sergio Apell2 555444 Sergio.Valenzuela@engendro.cl
1 Sergio Apell3 555444 Sergio.Valenzuela@engendro.cl

tambien es posible agregar campos de la tabla donde esta el campo XML
si existienran mas registros donde el campo Nombre del XML del campo XMLData sean 'Sergio', entonces mostrara mas registros.

/*************************************************************************

ejemplo Actualizado..... me confundí


DECLARE @TabXML TABLE (
ID INT,
DocXMLData XML
)
DECLARE @XML XML
SELECT @XML = '<ROOT><VALORES Nombre="Sergio" Apellido="Valenzuela" Fono="555444" Email="Sergio.Valenzuela@engendro.cl">
</VALORES>
<VALORES Nombre="Sergio" Apellido="Apell2" Fono="555444" Email="Sergio.Valenzuela@engendro.cl">
</VALORES>
<VALORES Nombre="Sergio" Apellido="Apell3" Fono="555444" Email="Sergio.Valenzuela@engendro.cl">
</VALORES>
<VALORES Nombre="Carlos" Apellido="Apell3" Fono="555444" Email="Sergio.Valenzuela@engendro.cl">
</VALORES>
</ROOT>'

INSERT INTO @TabXML
(
ID,
DocXMLData
)
VALUES
(
1,
@XML
)

SELECT tx.DocXMLData FROM @TabXML tx

SELECT --D.C.value(*)
ID,
D.C.value('@Nombre', 'Varchar(30)') as Nombre,
D.C.value('@Apellido', 'Varchar(30)') as Apellido,
D.C.value('@Fono', 'Varchar(10)') as Telefono,
D.C.value('@Email', 'Varchar(29)') as Email
FROM @TabXML
CROSS APPLY DocXMLData.nodes('ROOT/VALORES') D(c) -- recuerda que XMLData es el nombre del campo donde esta el XML
WHERE D.c.value('@Nombre', 'varchar(30)') = 'Sergio'


*************************************************************************/

PIVOT Dinamico SQL SERVER

Como podemos hacer un PIVOT dinamico en SQL Server??

Lo que vamos a hacer es crear un string que contenga la consulta que vamos a crear con la cantidad de valores que nosotros queramos en forma dinamica

me refiero si tenemos esto


para pivotear esto la documentacion dice que se debe hacer de la siguiente forma
link :
--------------------------------------
ejemplo link:
DaysToManufacture----AverageCost
0-----------------------------5.0885
1-----------------------------223.88
2-----------------------------359.1082
4-----------------------------949.4105

para pivotear

SELECT 'AverageCost' AS Cost_Sorted_By_Production_Days,
[0], [1], [2], [3], [4]
FROM
(SELECT DaysToManufacture, StandardCost
FROM Production.Product) AS SourceTable
PIVOT
(
AVG(StandardCost)
FOR DaysToManufacture IN ([0], [1], [2], [3], [4])
) AS PivotTable;


el resultado será

Cost_Sorted_By_Production_Days 0 1 2 3 4
AverageCost 5.0885 223.88 359.1082 NULL 949.4105

-----------------------------------------------------------

pero si se fijan ahi se debe incluir todos los valores de los dias, es decir que si existen 1000 dias se deben listar de 1 a 1000 días ([0], [1], [2], [3], [4]....[1000]), para hacer esto dinamico y si vemos que no solo pueden ser dias, sino, tipos de documentos, fechas, nombre, cuentas, etc, etc, recordar los nombre y escriibirlos uno a uno no es muy agradable entonces podemos hacer lo siguiente para crear dinamicamente el select que nos mostrará nuestro valores pivoteados tal como queremos.

continuando con mi ejemplo

el query que creará nuestro query es el siguiente:



DECLARE @Tipo VARCHAR(10) -- el largo 10 corresponde con el largo maximo del valor tipo que se pivoteara, si es mayor se debe aumentar
DECLARE @PVT VARCHAR(MAX)
DECLARE @PVT1 VARCHAR(MAX)
DECLARE @PVT2 VARCHAR(MAX)

SELECT @Tipo = MIN(Tipo) FROM TipoValor WHERE Tipo>'' -- select al menor tipo

SET @PVT1 = '' --en esta variable guardaremos los tipos entre comillas ''
SET @PVT2 = '' --en esta variable guardaremos los tipos entre corchetes []

--crearemos un ciclo para recorrer todos los tipos
WHILE NOT(@Tipo IS NULL)-- cuando se acaben los tipos de fechas
BEGIN
IF @PVT1 <> ''
SET @PVT1 = @PVT1 + ', '
SET @PVT1 = @PVT1+''''+@Tipo+'''' --tipos entre comillas

IF @PVT2 <> ''
SET @PVT2 = @PVT2 + ', '
SET @PVT2 = @PVT2+'['+@Tipo+']' --tipos entre corchetes

SELECT @Tipo = MIN(Tipo) FROM TipoValor WHERE Tipo > @Tipo --buscamos el siguente tipo de fechas mayor al anterior
END -- fin del ciclo

-- en la variable @PVT guadaremos como string el query del pivot
SELECT @PVT = 'SELECT Nombre,
'+@PVT2+ --tipos con corchetes
' FROM (SELECT
Nombre
Tipo,
Valor FROM
TipoValor WHERE
Tipo IN
( '+@PVT1+' )) as FEOC --tipos con comillas
PIVOT (MAX(Valor) -- el MAX es por si existe mas de un Tipo, se puede Sumar o agrgar cualquier funcion de agregacion
FOR Tipo IN (
'+@PVT2+' )) as P
GROUP BY
Nombre, '+@PVT2

SELECT @PVT -- Vemos el string donde esta el query del PIVOT completo

EXEC(@PVT) -- con el comando EXEC podemos ejecutar el string, que nos retornara el resultado que queremos


Todo esto nos deberia retornar los siguiente:



asi logramos agrupar por nombre, y pivoteamos el valor y los tipos, donde hay que notar el tipo T3 y que se repite para los nombre nom1 y nom3, donde podemos ver facilmente cuales típos y que valor tiene cada nombre

esta es la mejor opcion de mostrar la informacion, porque la otra opcion y que no es buena de mostrar es la siguiente

Select Nombre, Tipo, Valor from TipoValor order by Nombre

que mostrara algo asi como que no es lo optimo.

jueves, 10 de septiembre de 2009

Comando AT y Schtasks, crear o ejecutar tarea programada en otro equipo




Como podemos ejecutar una aplicacion en otra maquina?

Como podemos recargar nuestra aplicacion Qlikview en un equipo que no es nuestro(local)?

bueno, encontre estos dos comando que me solucionaron el problema

el primero AT:

AT nos permite crear, ver y borrar tareas programadas en un equipo remoto
por ejemplo

AT \\HOST HORA /interactive Comando(tarea) a ejecutar

AT \\192.168.1.2 12:00 /interactive "C:\Program Files\QlikView\Qv.exe" /r C:\QlikView\recarga.qvw"

AT: es el comando que permite agregar una tarea programada en otro equipo
si ejecutamos AT en la consola nos listara todas las tareas que se han agregado a la maquina local.
si ejecutamos AT \\HOST nos listara las tarea del HOST

\\HOST: es el nombre o IP de la maquina a la que queremos agregar la tarea programada

12:00: es la hora en que se ejecutara la tarea programada

/interactive: nos permite ver en primer plano la aplicacion o la tarea que se esta ejecutando, si omitimos este parametro se ejecutara en segundo plano.

"C:\Program Files\QlikView\Qv.exe" /r C:\QlikView\recarga.qvw": es la tarea que necesito que se ejecute, que en este caso es realizar la recarga de la aplicacion "recarga.qvw".

AT tiene algunos inconvenietes:
necesitas los permisos adecuados para poder agregar tareas en otra maquinas
cuando agrega una tarea el propietario de la tarea es el sistema y esto fue un gran problema, pues Qlikview tiene sus licencia por cada usuario del equipo, por lo que cuando intentaba hacer la recarga me pedia ingresar la licencia para el usuario del sistema.

Solucion?

finalmente el comando AT lo tuve que sustituir por el comando Schtasks que nos permite ejecutar en ese minuto una tarea programada en un equipo remoto.

significa que primero debemos crear en la maquina remota, con el usuario valido para qlikview, una tarea programada que no se debe ejecutar nunca por si solo, sino que cuando se le hace una llamada.
Con el comando Schtasks podemos realizar esto:

SCHTASKS /run /S \\192.168.1.2 /TN "Qv"

lo que ejecutara en el host 192.168.1.2 la tarea programada llamada "Qv"

/run: realiza la ejecucion de una tarea programada

/S \\HOST: indica que se ejecutara en ese host, si se omite se ejecutara en la maquina local

/tn "Qv": indica que se ejecutara la tarea programada llamada "Qv"

el comando SCHTASKS reemplazó al comando AT
ademas permite la ejecucion de una tarea programada /run, ademas de crear, borrar, terminar.

para mas info de este comando en SCHTASKS


para mas info de comando AT en AT

martes, 7 de julio de 2009

Archivo QVD - Qlikview

Los archivos QVD son archivos que almacenan datos que pueden ser de diferentes fuentes de datos, diferentes BD, archivos planos TXT, archivos Excel, etc.

Porqué utilizar archivos qvd?

-Son una forma de optimizar el tiempo de carga de los datos
-Permiten carga incremental
-Son recomendados por Qlikview (será una razón válida?)
-etc, ya se me ocurrirán

Cómo crear un archivo qvd?

en nuestro scrip :


//Nombre que le asignamos a la tabla
Nombre_Tabla:
//Permite carga desde la base de datos, permite las mismas intrucciones que se puedes
//realizar en la BD, notar que Antecede la palabra SQL antes de nuestro Select común
SQL SELECT *
FROM Nombe_Tabla_BD;

//Permite guardar la tabla antes cargada, notar que se debe indicar el nombre de la
//tabla que le asignamos a la tabla y no el nombre que tiene en la BD
STORE Nombre_Tabla
INTO Nombre_Archivo_QVD.qvd;
//es posible indicarle un directorio a esta ruta
//por ejemplo guardar en la carpeta ArchivosQVD
//INTO ArchivosQVD\Nombre_Archivo_QVD.qvd;


-La primer instrucción permite obtener datos desde nuestra Base de Datos
-La segunda guardar la tabla obtenida en un archivo QVD Nombre_Archivo_QVD.qvd

Como podemos invocar nuestro archivo QVD generado?

Desde cualquier aplicacion QVW podemos invocar desde nuestro Script de la siguiente froma:


Nombre_Tabla:
LOAD *
FROM Nombre_Archivo_QVD.qvd (QVD);


Notar que podemos volver a cambiar el nombre de la tabla asignado en nuestra nueva aplicacion QVW

Pero qué son realmente los archivo QVD?

Son archivos que en su estructura interna mantinene la forma de un archivo XML


<qvdtableheader>
<qvbuildno>#numero#</qvbuildno>
<creatordoc></creatordoc>
<createutctime>#fecha#</createutctime>
<sourcecreateutctime></sourcecreateutctime>
<sourcefileutctime></sourcefileutctime>
<sourcefilesize>-1</sourcefilesize>
<staleutctime></staleutctime>
<tablename>#nombre qvd#</tablename>
<fields>
<qvdfieldheader>
<fieldname>#titulo columna 1#</fieldname>
<bitoffset>#?#</bitoffset>
<bitwidth>#?#</bitwidth>
<bias>#?#</bias>
<numberformat>
<type>#Tipo#</type>
<ndec>#?#</ndec>
<usethou>#?#</usethou>
<fmt>#formato#</fmt>
<dec>,</dec>
<thou></thou>
</numberformat>
<noofsymbols>#numero de simbolo ?#</noofsymbols>
<offset>#?#</offset>
<length>#largo#</length>
</qvdfieldheader>

....
...
..
.
ETC




Pero si son archivos Qvd generados y mantiene la info en su interior,No tendremos la información actualizada?

Es uno de los inconvenientes de esta forma de utilizar los datos en nuestras aplicaciones.

Posible solución para tener datos(Archivos QVD) actualizados?

Solucion 1:
Crear una tarea programada en windows que nos actualice los datos, extrayendo automaticamente los datos de la Base de Datos a nuestro archivos QVD sin nuestra intervención por ejemplo todos los días en la mañana, para que todos los días podamos usar los datos completos al día de ayer.

Solucion 2:
Actualizar manualmente los archivos QVD, podremos usar los datos actulizados recientemente, pero si nuestros datos es una base de datos muy grande o se manejan instrucciones sobre funciones, vistas, procedimientos almacenados, triggers, u otra, nuestra carga puede tardar mucho tiempo (horas).

miércoles, 15 de abril de 2009

Qlikview - Habilitar o Deshabilitar Expresion en Tabla o Graficos

Si tenemos 10 Expresiones y queremos ver solo 1 o 4 o 8, etc a traves de una macro podemos habilitar o deshabilitar la expresion, lo que nos permite tener 1 tabla o grafico con distintas expresiones y asi no tenemos que crean n tablas o graficos segun las expresiones que deseamos ver.

para esto cree un campo INLINE en el script que se llama Expression

LOAD * INLINE [
Expression '->nombre campo
Expresion1
Expresion2
Expresion3

];

y le aplique en las propiedades de documento->macros->Field Event Triggers cuando OnLoad y OnChange la siguiente macro TypeExpr


sub TypeExpr
'obtengo los campos que deseo ver
set val=ActiveDocument.Fields("Expression").GetSelectedValues
'instancio el grafico o tabla que deseo habilita o deshabilitar las expresiones
set chart = ActiveDocument.GetSheetObject("CH15")
set cp = chart.GetProperties
'reviso cuales expresiones estan seleccionadas
a1=0
a2=0
a3=0
for i=0 to val.Count-1
if a1=0 then
if val.Item(i).Text="Expresion1" then
a1=1
end if
end if
if a2=0 then
if val.Item(i).Text="Expresion3" then
a2=1
end if
end if
if a3=0 then
if val.Item(i).Text="Expresion2" then
a3=1
end if
end if
next
'si la expresion1 esta seleccionada
if a1=1 then
set expr0 = cp.Expressions.Item(0).Item(0).Data.ExpressionData
expr0.Enable = true
else
set expr0 = cp.Expressions.Item(0).Item(0).Data.ExpressionData
expr0.Enable = false
end if
'si la expresion2 esta seleccionada
if a2=1 then
set expr1 = cp.Expressions.Item(1).Item(0).Data.ExpressionData
expr1.Enable = true
else
set expr1 = cp.Expressions.Item(1).Item(0).Data.ExpressionData
expr1.Enable = false
end if
'si la expresion3 esta seleccionada
if a3=1 then
set expr2 = cp.Expressions.Item(2).Item(0).Data.ExpressionData
expr2.Enable = true
else
set expr2 = cp.Expressions.Item(2).Item(0).Data.ExpressionData
expr2.Enable = false
end if

'habilito o deshabilito las expresiones seleccionada
chart.SetProperties cp

end sub

miércoles, 25 de febrero de 2009

Qlikview - Include para VBscript

Utilizando el Qlikview necesito unificar para muchos archivos qvw el mismo Modulo (donde se agregan las subrutinas y las funciones), por lo que tengo que crear un archivo vbs, donde tenga todo lo que requiero y desde los archivos qvw tengo que llamar, incluir o importar estas funciones.

En VBscript no existe una instrucción donde yo pueda incluir desde un archivo vbs otro vbs.

Si tenemos el archivo1.vbs que imprime un mensaje "Hello Word"


sub HolaMundo
msgbox("Hello Word")
end sub


y queremos llamar desde otro archivo vbs(Archivo2.vbs) este mensaje, no existe una funcion como la de php por ejemplo
include("nombre.php");


ahora, buscando en la web encontre una solución a esto, pero tenemos que crear una subrutina que lo simule.

entonces debemos hacer lo siguiente, tenemos nuestras funciones o subrutinas en

archivo1.vbs



sub holaMundo
msgbox("Hello World")
end sub


entonces debemos agregar en nuestro qrchivo2.vbs lo siguienre para poder utilizar las funciones o subrutinas de Archivo1.vbs.
archivo2.vbs

Import "C:\Archivo1.vbs"

Sub Import(ByVal strFile)
Set objFs = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
strFile = WshShell.ExpandEnvironmentStrings(strFile)
file = objFs.GetAbsolutePathName(strFile)
Set objFile = objFs.OpenTextFile(strFile)
strCode = objFile.ReadAll
objFile.Close
ExecuteGlobal(strCode)
End Sub



Como yo estoy aplicando esto a Qlikview, realizo lo siguiente

creo el archivo1.vbs con todas las funciones y subrutinas y desde los archivos qlikview(qvw) agrego en el módulo lo que se debe agregar en el archivo2.vbs y asi puedo modificar una funcion en el archivo1.vbs y cambiara en todos los archivos Qlikview (qvw).


Asi soluciono mi problema de modificar todos los archivos con las mismas funcionalidades cada vez que se hace un cambio.






fuente: asp free.com <-- aqui