Pattern: CrossTable entre 2 dimensiones
Se me ha presentado en varias oportunidades, que en aplicaciones GeneXus WEB necesito tener una tabla de cruces de datos. Esta es una tabla donde se muestre una dimension en las columnas y otra dimension en las filas, poniendo algun indicador (suma o cuenta) en las celdas internas de la tabla.
Ejemplo:
Factura
*NroFactura
Cliente
Producto
Importe
y generar una tabla del tipo
Esto es relativamente facil de implementar con el codigo: (el ejemplo va sin TOTALES).
Hay que programar un Webpanel, que unicamente tenga un FreeStyle subfile, con una variable &Texto=C(100). Las columnas se setean en runtime.
Event Load
&Columnas=0
for each Cliente
&Columnas +=1
endfor
Grilla.Columns = &Columnas + 1
//Cargo primer casillero
&Texto='..'
Load
//Cargo Titulos superiores
for each Cliente
// where Condicion de clientes
&Texto=ClienteNombre
&Texto.FontBold=1
Load
endfor
for each Producto
//Cargo Titulo de la fila
&Producto=Producto
&Texto=ProductoDsc
&Texto.FontBold=1
&Texto.Link=link('')
Load
for each Cliente
&Cliente=Cliente
//Cargo la celda con Cliente y Producto Instanciado.
do 'Acumulo'
&Texto.FontBold=0
Load
endfor
endfor
EndEvent // Start
Sub 'Acumulo'
&Importe=0
for each
Where Cliente=&Cliente
Where Producto=&Producto
&Importe += Importe
endfor
If Not &Importe.IsEmpty()
&Texto=str(&Importe)
&Texto.Link=Link(hListoFacturas,&Cliente,&Producto)
else
&Texto.SetEmpty()
&Texto.Link=link('')
endif
EndSub
Estaría bueno implementarlo para la ROCHA (es fácil y de ingenio), aunque aun no hay demasiada documentación sobre como hacerlos.
PD: Ojo que no es aplicable a todos los casos, pues si la matriz generada es muy dispersa o si tenes alguna dimension que sea de una cardinalidad muy grande, puede consumir muchisimos recursos hacerlo.
Queda como ejercicio interesante, hacer un DataProvider que realice la consulta (agrupando por las dimensiones y haciendo la suma/cuenta) y despues procesar el SDT.
El dataprovider deberia hacer
"SELECT DIMENSION1, DIMENSION2,SUM(INDICADOR) FROM TABLA GROUP BY
DIMENSION1, DIMENSION2"
También puede tener problemas de performance si la cardinalidad de la tabla de facturas es muy grande. Hay que usarlo con cariño.
Ejemplo:
Factura
*NroFactura
Cliente
Producto
Importe
y generar una tabla del tipo
| Cliente1 | Cliente2 | Cliente3 | Cliente4 | Cliente5 | Total |
Producto1 | | | 3000 | | | 3000 |
Producto2 | 200 | | 100 | 45 | | 345 |
Producto3 | | | | | 1 | 1 |
Total | 200 | | 3100 | 45 | 1 | 3346 |
Esto es relativamente facil de implementar con el codigo: (el ejemplo va sin TOTALES).
Hay que programar un Webpanel, que unicamente tenga un FreeStyle subfile, con una variable &Texto=C(100). Las columnas se setean en runtime.
Event Load
&Columnas=0
for each Cliente
&Columnas +=1
endfor
Grilla.Columns = &Columnas + 1
//Cargo primer casillero
&Texto='..'
Load
//Cargo Titulos superiores
for each Cliente
// where Condicion de clientes
&Texto=ClienteNombre
&Texto.FontBold=1
Load
endfor
for each Producto
//Cargo Titulo de la fila
&Producto=Producto
&Texto=ProductoDsc
&Texto.FontBold=1
&Texto.Link=link('')
Load
for each Cliente
&Cliente=Cliente
//Cargo la celda con Cliente y Producto Instanciado.
do 'Acumulo'
&Texto.FontBold=0
Load
endfor
endfor
EndEvent // Start
Sub 'Acumulo'
&Importe=0
for each
Where Cliente=&Cliente
Where Producto=&Producto
&Importe += Importe
endfor
If Not &Importe.IsEmpty()
&Texto=str(&Importe)
&Texto.Link=Link(hListoFacturas,&Cliente,&Producto)
else
&Texto.SetEmpty()
&Texto.Link=link('')
endif
EndSub
Estaría bueno implementarlo para la ROCHA (es fácil y de ingenio), aunque aun no hay demasiada documentación sobre como hacerlos.
PD: Ojo que no es aplicable a todos los casos, pues si la matriz generada es muy dispersa o si tenes alguna dimension que sea de una cardinalidad muy grande, puede consumir muchisimos recursos hacerlo.
Queda como ejercicio interesante, hacer un DataProvider que realice la consulta (agrupando por las dimensiones y haciendo la suma/cuenta) y despues procesar el SDT.
El dataprovider deberia hacer
"SELECT DIMENSION1, DIMENSION2,SUM(INDICADOR) FROM TABLA GROUP BY
DIMENSION1, DIMENSION2"
También puede tener problemas de performance si la cardinalidad de la tabla de facturas es muy grande. Hay que usarlo con cariño.
Hola,! tiempo atrás un colega me pasó el link, y probé el tips del CrossTable... espectacular!
ResponderBorrarA modo de ejemplo, en un cuadro tenemos 10 filas en la Dimensión 1 y 100 en la Dim.2, La tabla cross es de 100.000 reg... en unos 15 seg. despliega el cuadro resultante... luego hicimos unos cambios a nivel diseño de BD para mejorar los tiempos..
Es un chichecito..., una solución simple y elegante.
Edgardo
Edgardo:
ResponderBorrarMe alegro que te sirviera...
Hola Enrique, no se si aun esta abierto a consultas este blog, pero probe el caso que mencionas y funciona bien, cuando tenemos 2 dimensiones.
ResponderBorrarEl caso que tengo yo es que tengo solo 1 tabla, en la que quiero armar un grid en un WP, pero que cierto dato se utilice para las columnas y el resto a las filas.
Explico mejor:
1) tengo esta tabla temporal, que cargo con resultados del consumo de un webservice:
-CodigoProd (CCAR)
-Proveedor (A,B,etc)
-PlanTarifario (1,2,etc)
-Precio (100,110,etc)
Codigo proveedor PlanTarifario Precio
CCAR A 1 100
CCAR A 2 120
CCAR A 3 130
CCAR A 4 140
CCAR A 5 150
CCAR B 1 100
CCAR B 2 120
CCAR B 3 130
CCAR B 4 140
CCAR B 5 150
CCAR C 1 100
CCAR C 2 120
CCAR C 3 130
CCAR C 4 140
CCAR C 5 150
CCAR D 1 100
CCAR D 2 120
CCAR D 3 130
CCAR D 4 140
CCAR D 5 150
CMMT A 1 200
CMMT A 2 210
CMMT A 3 220
CMMT A 4 230
CMMT A 5 240
CMMT B 1 200
CMMT B 2 210
CMMT B 3 220
CMMT B 4 230
CMMT B 5 240
CMMT C 1 200
CMMT C 2 210
CMMT C 3 220
CMMT C 4 230
CMMT C 5 240
CMMT D 1 200
CMMT D 2 210
CMMT D 3 220
CMMT D 4 230
CMMT D 5 240
2) Necesito en las columnas los proveedores sin repetir (A,B,C,etc)
Necesito en las filas codigo(CCAR) y para cada codigo los planes tarifarios(1,2,etc) y para cada plan tarifario su correspondiente precio ubicado en la columna correspondiente al proveedor(A,B,C,etc).
Lo estaba analizando con tabla dinamica de Excel y necesitaria que quede asi:
A B C D E
CCAR 1 120,00 151,30 98,10 0,00 200,41
2 265,00 238,85 234,90 0,00 238,85
3 286,00 264,35 261,90 0,00 272,00
4 286,00 264,35 261,90 283,00 0,00
5 316,00 288,15 288,90 0,00 0,00
CMMT 1 120,00 151,30 98,10 0,00 200,41
2 265,00 238,85 234,90 0,00 238,85
3 286,00 264,35 261,90 0,00 272,00
4 286,00 264,35 261,90 283,00 0,00
5 316,00 288,15 288,90 0,00 0,00
No me doy cuenta si este es el metodo para resolver esta necesidad o si tengo que intentar otra cosa.
Muchas gracias!
Lo podes hacer con un corte de control con un for each anidado y grabar cuando cambia el primer codigo.
ResponderBorrarHola Enrique estoy probando asignar la propiedad grid.columns = &col, y no lo está tomando, probé poner esa asignación en diferentes eventos load de la grilla start refresh y nada sigue mostrando 1 sola columna
ResponderBorrar