Mostrando entradas con la etiqueta expresión. Mostrar todas las entradas
Mostrando entradas con la etiqueta expresión. Mostrar todas las entradas

domingo, 18 de noviembre de 2018

► Cómo evitar IF anidados


Cuando tenemos que aplicar expresiones distintas en función del valor que tome una dimensión, podemos hacerlo de varias formas.

Ej: If (dimension =1, expr1,
        If (dimension=2, exp2,
            If (dimension=3, exp3,
                If (dimension=x, exprx))))

      1Usando la función PICK(). Esto sólo lo haremos cuando los valores de la dimensión sean números naturales.

            Pick(dimensión, expr1, expr2, expr3……exprx)

Una forma rápida de crear esta función pick es hacerlo dinámicamente usando CONCAT() en lugar de escribir una función larguísima que contenga todas las expresiones. Así mejoramos el mantenimiento y la legibilidad.
Para hacerlo, hay que meter todas las expresiones en un campo en una isla de datos. El origen puede ser un inline, una Excel o un fichero de texto. Lo único que hay que tener en cuenta es que deben estar ordenadas según el valor de la dimensión y el orden que ocuparán en la función PICK().
Ejemplo: Imaginemos que tenemos una dimensión “Dim_x” con los valores 1, 2 y 3 y que según el valor que tome se aplique una expresión u otra: Para el valor 1 hará la suma del campo1, para el valor 2 hará la media y para el valor 3 obtendrá la moda.
Tenemos este inline:

ISLA_DATOS:
LOAD * INLINE [
Orden,    Expresion
1,        SUM(campo1)
2,        AVG(campo1)
3,        MODE(campo1)
];

En las expresiones de gráficos u objetos sustituiremos los if anidados por esta única expresión:

PICK(Dim_x, $(=CONCAT(Expresion, ’,’ ,Orden)))

Observad que los argumentos de CONCAT son las columnas del INLINE
 

    2)   Con expansión del signo $. De esta forma los valores de la dimensión no tienen por qué ser numéricos.
A diferencia del ejemplo 1 en el que las diferentes expresiones se introducían en un campo de una isla de datos cuyo origen era un inline, un Excel o cualquier otra fuente, aquí crearemos una variable por cada expresión.
El nombre de cada variable debe tener un formato muy concreto: una raíz común + cada valor posible de la dimensión:

Ejemplo 1: Suponiendo que tenemos una dimensión “Dim_x” con los valores 1, 2 y 3
Creamos las variables:

       SET Var_1 = SUM(campo1);
      SET Var_2 = AVG(campo1);
      SET Var_3 = MODE(campo1);

Ejemplo 2: Suponiendo que la dimensión “Dim_x” tenga los valores Madrid, Málaga y Bilbao

Creamos las variables

SET Var_Madrid = SUM(campo1);
          SET Var_Málaga = SUM(Campo1*0,05);
          SET Var_Bilbao =  SUM(campo1*0,02);

En los objetos sustituimos los if anidados por esta expresión:

                             =$(='Var_'&ONLY(Dim_x))


3)  Usando la función ALT().
Esta opción es la menos recomendable porque se ejecuta casi igual que los IF anidados, pero al menos facilita la lectura y comprensión de la expresión. 
Se debe usar sólo cuando no se puedan evitar los IF anidados, como por ejemplo en el Script.
Sólo funciona cuando los valores devueltos son números. No funciona si devuelve cadenas de caracteres.
Usando el ejemplo 2, lo podemos transformar por:


 ALT(
      IF(Dim_x=’Madrid’, SUM(campo1)),
      IF(Dim_x=’Málaga’, SUM(Campo1*0,05)),       
      IF(Dim_x=’Bilbao’, SUM(campo1*0,02)),
      0
    );

► Variables con fechas (YTD, MTD, AñoAnterior…. Etc)


Lo primero que debemos hacer es crear un campo llamado Periodo asociado a cada fecha. Este campo tiene el formato YYYYMM y se puede crear con la fórmula (Año*100 + Mes).

Para los ejemplos vamos a tomar como “fecha actual” la mayor de todas las seleccionadas (en caso de que se puedan seleccionar varios meses). 

Partimos de que tenemos un calendario maestro con los campos Año, Mes y Día

Las expresiones a utilizar son del tipo:

SUM ({<Año=,Mes=, Día=, Periodo={">=$(vL.InicioAño) <=$(vL.PeriodoActual)"}>} Campo_A_Sumar)  //esto calcula el acumulado YTD

=SUM({<Año={"<=$(vL.AñoActual) >=$(=$(vL.AñoActual)-1)"}, Mes={"$(=$(vL.MesActual))"} >} Campo_A_Sumar//Calcula el acumulado YTD también pero de este año y de los mismos meses del año anterior. Del año anterior sólo toma los mismos meses que hayan transcurrido del año actual.


Type
Variable Name
Value
Comment
SET
vL.AñoActual
=Max(Año)
Año Actual
SET
vL.AñoAnterior
=Max(Año)-1
Año Anterior
SET
vL.InicioAño
=num(MAX(Año)&'0101')
Día de Inicio Año Actual
SET
vL.InicioAñoAnterior
=num((MAX(Año)-1)&'0101')
Día de Inicio año Anterior
SET
vL.MesActual
=num(Month(MAX([fecha_referencia])))
Mes actual en número. No es Max(Mes) porque el año más grande puede pertenecer al año anterior.

SET
vL.PeriodoActual
=MAX(Periodo)
El periodo actual es el mayor de los seleccionados
SET
vL.PeriodoAnterior
=IF(MAX(Mes)=1 , num((MAX(Año)-1)&'12')  ,  num(MAX(Periodo)-1))
AñoMes anterior al PeriodoActual
SET
vL.PeriodoAñoAnterior
=((MAX(Año)-1)*100) + MAX(Mes)
Mismo periodo que el actual pero del año anterior
SET
vL.InicioMes
=num(MAX(Periodo)&'01')
Día de inicio del PeriodoActual
SET
vL.InicioMesAnterior
=IF(MAX(Mes)=1 , num((MAX(Año)-1)&'1201')  ,  num(MAX(Periodo)-1&'01'))
Día de inicio del periodo anterior a PeriodoActual
SET
vL.TrimAnterior
=if(MAX(Mes)>3, (MAX(Año)*100)+num((MAX(Mes)-3),'00'), (MAX(Año)-1)&pick(MAX(Mes),'10','11','12'))
3 periodos antes al PeriodoActual
SET
vL.DiaMesActual
=MAX(PeriodoDia)
Día mayor de los seleccionados. Formato YYYYMMDD
SET
vL.DiaMesAnterior
=If(MAX(PeriodoDia)=text(date(monthend(date#(MAX(PeriodoDia),'YYYYMMDD')),'YYYYMMDD')),
text(date(monthend(date#(IF(MAX(Mes)=1 , num((MAX(Año)-1)&'1201')  ,  num(MAX(Periodo)-1)&'01'),'YYYYMMDD')),'YYYYMMDD')),
IF(MAX(Mes)=1 , num((MAX(Año)-1)&'12'&num(MAX(Día),'00'))  ,  num(MAX(Periodo)-1)&num(MAX(Día),'00'))
 )
Mismo día del mes anterior. Si el día actual es el último del mes, se calcula el último día del mes anterior. Este mes puede tener 31 días y el anterior 28, 29 ó 30
SET
vL.DiaAñoAnterior
=((MAX(Año)-1)*10000) + (MAX(Mes)*100) + num(MAX(Día),'00')
Mismo día del Año anterior. Puede haber un problema con el 29 de Febrero.
SET
vL.MesesTranscurridos
floor((MonthStart("Fecha Reciente") - monthStart("Fecha Antigua"))/30)
Meses transcurridos entre dos fechas.

► Cambiar el orden predeterminado en un gráfico


Cuando queremos mostrar algo ordenado, pero queremos controlar nosotros en qué orden tienen que aparecer los valores, podemos hacerlo de 3 formas:

1.- A partir de una tabla INLINE que no desaparecerá del modelo de datos.

Map_Orden:
LOAD * Inline [
Ciudad,     Orden
París,      1
Madrid,     2
Londres,    3
Tokyo,      4
Roma,       5
Moscú,      6
]
;
 

Después pondremos como expresión de ordenación en Propiedades del grafico à Pestaña Ordenar (sort) à Ordenar Por à Expresion(expression) y ahí colocar el nombre del campo ‘Orden’ de la tabla Inline.

2.- Combinando una tabla de mapeo y DUAL. Esta tabla no formará parte del modelo de datos.
Map_Orden:
Mapping LOAD * Inline [
Ciudad,     orden
París,      1
Madrid,     2
Londres,    3
Tokyo,      4
Roma,       5
Moscú,      6
]
;
 
Datos:
LOAD
........... //Lista de campos
DUAL
(Ciudad, ApplyMap('Map_Orden', Ciudad)) as Ciudad,
........... //Lista de campos
FROM  ........... //Tabla, fichero… etc.

Después pondremos como expresión de ordenación en Propiedades del grafico à  Pestaña Ordenar (sort) à Ordenar Por à Valor numérico


3.-  Escribir directamente los valores en el orden deseado usando la función WildMatch() en Propiedades del grafico à  Pestaña Ordenar (sort) à Ordenar Por à Expresion(expression)

Wildmatch(Ciudad,’Paris',’Madrid’,’Londres’,’Tokyo’,’Roma’,’Moscú’)

► Comprobar que un campo sólo tiene un valor

Algunas veces necesitamos realizar operaciones sobre objetos dependiendo de si un campo tiene sólo un valor o más de uno distintos.
Ejemplo: Se puede usar para mostrar el escudo de una localidad cuando el usuario sólo tiene acceso (restringido por la sección de acceso) a esa localidad y a ninguna más.

La mejor forma de hacerlo es con la expresión: not IsNull(Only({1} <campo>))

En nuestro ejemplo sería not IsNull(Only({1} Localidad))


En condiciones controladas, se puede usar la función GetSelectedCount (), pero no podemos esperar que el usuario haga una selección o no.
Si no hace selecciones, no funcionaría. Si hace varias selecciones en otros campos, esas selecciones también afectan al campo de la función GetSelectedCount de modo que puede no quedar ningún valor seleccionable. En este último caso habría que crear una expresión set analysis bastante compleja que limpie todos los campos candidatos a hacer selecciones sobre ellos:
{<campo1=, campo2=,…..campoN=>}


Con ONLY( {1} <campo>) no dependemos de las selecciones realizadas.
Esta función devuelve el valor en caso de que todos los registros tengan el mismo valor o nulo en caso de que los registros tengan varios valores distintos.

Es el equivalente a hacer COUNT({1} DISTINCT Localidad), pero la función Count siempre es más pesada y afecta negativamente al rendimiento.

Otra forma de hacerlo es usando la función inter-registro FieldValueCount('campo'), que devuelve el nº de valores distintos que tiene un campo. Observese que el campo va entre comillas simples.