368
Necesitamos poder agrupar, acceder y analizar la información sobre la operativa de nuestro negocio, obteniendo información confiable que nos ayude a tomar decisiones. A esto le llamamos inteligencia de negocio (Business Intelligence). Por ejemplo, en nuestro sistema de ventas y facturación, queremos sumarizar las ventas efectuadas, agrupadas por país, por cliente, y por fecha de facturación. Por ejemplo, podríamos querer sumarizar los totales de facturas agrupando de la siguiente manera: Primero por país, Luego, para cada país, agrupando por cliente, y finalmente, por fecha de facturación. Así, como podemos ver en el esquema (cubo) de arriba, cortaríamos primero por el eje Country, luego, dentro de este, por el eje Customer, y a partir de este, por el eje Invoice Date. Country Customer Invoice Date Sum(InvoiceAmount) Uruguay Julia 01/01/09 150 01/02/09 145 01/03/09 25 Total de Julia : 320 Diego 01/01/09 300 01/02/09 550 Mary 01/01/09 890 369
Si sumamos por los criterios anteriores en ese orden (country, customer, invoice date), entonces vamos obteniendo los totales que resultan de sumar verticalmente en el cubo de arriba, en el plano correspondiente a Uruguay. Pero también podríamos querer sumarizar los totales de facturas, ahora agrupando de esta otra manera: Primero por país; luego, para cada país, agrupando por fecha de facturación, y finalmente, por cliente. Para ello, sumaríamos horizontalmente t dentro del plano Uruguay del esquema (cubo) de arriba. 370
Teniendo la información base almacenada (datos), podemos, pues, sumarizar agrupando por los criterios que deseemos. Podemos elegir ver la información requerida en tablas dinámicas (pivot tables), que permiten manejar información multidimensional, es decir, bajo múltiples perspectivas de análisis. Por ejemplo, podemos ver la información agrupada de otra manera, podemos ver los datos como columnas, y no como filas, o incluso 371
como páginas. En el ejemplo, observar que podemos seleccionar algunas de las fechas de factura, para poder sumarizar sólo por esas fechas, mostrando en la página el resultado. Ahora bien: Cómo especificamos esta consulta en GeneXus sobre la base de datos operacional? 372
Especificamos la consulta en GeneXus, a través del tipo de objeto Query. Obsérvese que la información de los ejes del cubo que mostramos antes, aparece bajo el nodo Attributes, así como los datos (en este caso uno solo, Sum(InvoiceAmount)). Estos son los elementos que definen la consulta. Observación: Como en el caso del corte de control, deberá existir una tabla extendida que contenga a todos los atributos involucrados, y cuya tabla base hará las veces de la tabla base del corte de control. 373
Si resolvemos el reporte como un procedimiento con corte de control, no tendremos ninguna libertad. Los datos deberán salir en el orden especificado, cortados por los criterios especificados, y el usuario no tendrá la libertad de pivotear, visualizando la información con otro orden y agrupamiento. A su vez, sólo podrá utilizar los print blocks para mostrar la información, que restringe lo que se puede mostrar (no podrá hacer gráficas, ni tablas, etc., como sí ocurrirá con el objeto Query). 374
Podrá visualizar la información resultante de la consulta en forma gráfica: como una gráfica de barras, de torta, etc. Pero no sólo. También podrá visualizarla 375
como tabla plana. O incluso 376
como tabla dinámica (pivot table). Esta tabla es manipulable, como ya vimos, y el usuario final podrá reordenar columnas, mostrar la información como filas, columnas o páginas, etc. 377
Business Intelligence (BI): es un conjunto de procesos, tecnologías y herramientas que nos permiten agrupar, acceder y analizar la información sobre la operativa de nuestro negocio y poder obtener información confiable y oportuna que nos ayude a la hora de la toma de decisiones. En GeneXus lo logramos a través del objeto Query, utilizando para la salida de datos, como veremos, el User control: Query Viewer.
Además de la estructura, en la que se definirá la consulta en sí misma, contamos también con dos secciones que proveen mecanismos de prototipación para la definición de la misma. Con estas secciones podremos ir viendo si la consulta está siendo bien definida y si la misma nos está devolviendo la información que es requerida. Contamos con la posibilidad de visualizar la sentencia SQL que se va a ejecutar en la base de datos para traer la información, esto se ve en la sección SQL Statement del objeto. Veamos que en la ventana de Output de la KB se muestra que se está generando la sentencia SQL y el resultado de la misma. Si hubiera algún error en la definición de la consulta, por ejemplo que los atributos que la componen no están relacionados, será informado en esta ventana. Pero sin duda la funcionalidad más útil en lo que respecta a la prototipación es la posibilidad de visualizar un preview de la salida de la consulta en una gráfica, tabla plana o tabla dinámica, 100% funcional, trabajando desde GeneXus. Podremos ver cómo será la salida que verán los usuarios (incluso si los datos son los mismos que en producción, veremos exactamente los mismos datos) y trabajar en la tabla dinámica, y en caso de detectar alguna omisión o error, corregirlo y volver al preview. Aquí se ejecuta la sentencia SQL que se generó para el objeto. Pasemos, ahora sí, a estudiar la sección más importante, aquella donde se define la consulta: la estructura. 379
En lo que sigue estudiaremos las distintas posibilidades de información que puede incluirse en el nodo Attributes, para especificar la salida de la consulta. Existen las siguientes posibilidades que veremos a continuación: Atributos Funciones de agregación (simples o condicionadas) Expresiones 380
La columna Description indicará la etiqueta para el atributo en la salida de la consulta. En la definición de una consulta, la agregación por defecto que se le asocia a cada atributo determina su posición en la tabla dinámica (pivot table): área de ejes o datos. Ejes: son los elementos por los cuáles se corta la información, se pueden pivotear, etc., y son asociados automáticamente a los atributos sin agregación. En caso de manipular una tabla dinámica a su vez podrá seleccionar cuatro tipos de ejes (Filas, Columnas, Páginas y Oculto). Datos: estos elementos se sumarizan según los ejes y toman valores para cada combinación de ejes. Están asociados a los atributos con alguna agregación. Este tipo de atributo debe ser sumable (no se permiten atributos de tipos de datos no numérico en el área de datos de una tabla dinámica). Para Count no se requiere que sea numérico, ya que el atributo se utiliza para contar las ocurrencias de registros. Cuando se coloca un atributo suelto, sin función de agregación, pero es Numérico con decimales, la función Sum es automáticamente aplicada, y se considera como dato. Ejemplo: si se coloca InvoiceAmount y no Sum(InvoiceAmount). 381
Las agregaciones que es posible obtener como datos de una consulta son tres: Sum (suma), Count (cuenta) y Average (promedio). Puede verse en el objeto Query de la imagen, cada una de esas funciones aplicadas a distintos atributos, para obtener distintos datos del cliente de cada país. Las funciones de agregación pueden anidarse. Nota: No todas las funciones de agregación aplican a todos los tipos de atributos. tib t Sum y Average sólo están disponibles para atributos numéricos. 382
Las funciones de agregación pueden mostrarse como porcentaje. Así, si en lugar de querer obtener los totales de ventas por cliente, en dólares, se desea mostrar el porcentaje respecto al total de ventas, entonces alcanza con configurar la propiedad Percentage en True. En los filtros globales se tiene CountryName = Uruguay lo que hace que el 100% corresponda a las facturas de Uruguay. 383
La cláusula DefinedBy del Count es análoga a la del for each. Permite indicar otro atributo para la determinación de tabla base. Aquí entenderá que no deberá contar las ocurrencias de CustomerId en la tabla Customer, sino en la Invoice Además, en este caso especial, determina que deberá contar los valores distintos de CustomerId. 384
Observemos que la función Average admite la cláusula By, para poder establecer por qué criterio se desea promediar. En el primer caso (sin cláusula By), se sumarán los InvoiceAmount de todas las facturas del cliente, y se dividirá por la cantidad de facturas. En el segundo, en cambio, se agruparán las facturas por fecha, y la suma del InvoiceAmount se dividirá por la cantidad de grupos de fechas. Es decir, se promediará de acuerdo a la cantidad de fechas distintas. En este caso necesitamos la cláusula By para lograr ese agrupamiento. 385
En este ejemplo, como podemos ver, se presenta el mismo dato Sum(InvoiceAmount) pero filtrando por dos condiciones distintas: Para cada país y cada cliente se quieren obtener: La suma de las facturas que están pendientes de procesamiento (no se han incluido en un recibo aún) La suma de las facturas que ya han sido procesadas (y se han incluido en un recibo). Notas: Obsérvese que en la descripción por defecto, aparece el primer dato como Sum(Invoice Amount) y el segundo, con un sufijo numérico: Sum( Invoice Amount) (2). Como además se está filtrando en los filtros globales por Uruguay, es el único país que figura en la salida. 386
En este otro ejemplo podemos ver cómo es posible condicionar antes o después de realizar la agregación. En el primer caso, de todas las facturas de un país, se sumarizan únicamente aquellas que superan los U$S 500. En el segundo, en cambio, solamente se mostrará un país, si la suma de todas sus facturas supera los U$S 1000. 387
Además de lo anterior, pueden especificarse en el nodo Attributes expresiones aritméticas con atributos, aggregate, condicionadas (esto funcionará a partir de próximos updgrades de la evolution) y funciones aplicadas a los atributos. Entre las funciones disponibles están: AddMth AddYr EoM YMDHMStoT YMDtoD Lower LTrim PadL PadR RTrim Str StrReplace Substr Trim Upper Age Dow Hour Int Len Minute Month Second StrSearch StrSearchRev Year Round Trunc Val 388
Parameters: aquí se definen parámetros que recibirá la consulta y son utilizados dentro de algún filtro. En las propiedades se puede configurar un valor por defecto para el parámetro. Global Filters: aquí se definen filtros generales para los datos de la consulta. Se tienen disponibles varios tipos (rangos, listas, operador like y utilización de subconsultas). Es posible definir cualquier nivel de anidación de estos filtros y parametrizarlos utilizando los parámetros definidos en la parte anterior. Dentro de los rangos, como caso particular, aparecen los operadores aritméticos: >, >=, =, <>, <, <=. Para filtrar en base a valores obtenidos de la base de datos, se permiten las subconsultas. En el ejemplo, queremos obtener para cada vendedor que ha vendido el producto recibido por parámetro, todos los productos que éste vende. Para saber qué vendedores han vendido el producto recibido por parámetro, colocamos la subconsulta. Observemos que en este caso se está utilizando su resultado como una lista de valores. Una subconsulta deberá devolver uno o muchos valores, según corresponda. Si se usa con =, >, >=, <, <=, o <>, tiene que devolver un sólo valor. Ej: att = subconsulta. También debe devolver un sólo valor cuando se lo usa con un IN y una lista de valores donde la subconsulta es uno de esos valores. Ej: att IN [valor1, valor2, subconsulta, valor3]. Por ejemplo, la lista podría ser de los clientes 1, 2 y 3, y además el que compró más (éste último se obtiene con una subconsulta). O también cuando se trata de un rango: att IN [valor1 to subconsulta]. El único caso donde la subconsulta puede devolver N valores es cuando se la usa con un IN aellasola.ej:att IN [subconsulta]. Por ejemplo, una consulta que devuelva los clientes que compraron más de un determinado monto, o nuestro caso en el ejemplo de arriba. Para ver las restricciones en cuanto a los filtros, más ejemplos, así como los diagramas formales de sintaxis, diríjase al artículo del Community Wiki Query Object: filters. 389
Se ofrecen dos tipos de filter groups : AND y OR. 390
Este nodo sólo aplica cuando la salida es una tabla plana o una gráfica. Lo que aquí se coloque va directamente al select. Si se colocan varios atributos, genera un ORDER BY Att1, Att2, Attn. 391
Qué consultas son válidas y cómo se resuelven? 1. Deberá existir alguna tabla extendida que contenga a todos los atributos sin agregación. 2. Si la consulta no contiene agregaciones condicionales (es decir, con filtros), y todos los atributos sin y con agregación de la consulta pertenecen a una misma tabla extendida, entonces el select de la consulta va sobre la tabla extendida que contiene todos los atributos y suma, cuenta, promedia, los atributos con agregación ( datos ) agrupando por los atributos sin agregación ( ejes, los atributos por los cuales se cortan los datos). Ej: CountryName CustomerName Sum(InvoiceAmount) Count( InvoiceAmount ) 3. Si no es así, (no es posible encontrar una tabla extendida que contenga todos los atributos y/o existen atributos con agregaciones condicionales) entonces GeneXus arma grupos de datos que comparten una extendida, y todos esos datos los resuelve juntos. Por cada grupo de datos se hace un select y luego todos los selects se unen con un Full join. Ej: Subconsulta 1 Subconsulta 2 CountryName CountryName CountryName CustomerName CustomerName CustomerName Sum(InvoiceAmount) Sum(InvoiceAmount) Sum( BillAmount) Sum (BillAmount) Count( InvoiceId) Count (InvoiceId ) 4. Las agregaciones condicionales (con filtros) determinan grupos separados. Ej: Sum(InvoiceAmount) where automáticamente se agrupa con los atributos sin agregación (CountryName y CustomerName) y se resuelve separadamente del resto. 392
Ahora bien, tengo definidas mis consultas, ya vi el preview de cada una y la informacion que devuelven es la que estoy necesitando consultar. Por otro lado tengo mi aplicación web. Naturalmente surgirá el requerimiento de ver la información extraída con los objetos query dentro de la aplicación, o sea, necesitamos algún elemento que nos permita integrar las consultas en la aplicación. Este elemento, es un control Web del tipo denominado User Control, y su nombre es Query Viewer. 393
El funcionamiento es bastante simple e idéntico al de cualquier otro tipo de user control de GeneXus. Si queremos insertar un control Query Viewer en un web form (Web panel o Transacción), simplemente debemos arrastrar el control hacia el form en la posición deseada y configurar una serie de propiedades (como en el caso de cualquier user control). 394
Además de un nombre para el control y propiedades para la apariencia del mismo, debemos configurar las dos propiedades más importantes, estas son: Object, que indica la consulta que se mostrará en el control y Parameters, que indica la variable con la cual se pasarán los valores de los parámetros para la consulta en caso de que ésta los requiera. También tenemos la propiedad Type, que permite configurar el tipo de salida. La mayoría de las propiedades pueden configurarse tanto estática como dinámicamente. Al insertar un control Query Viewer en el web form de un objeto, como en casi todo user control, se consolidan algunos SDT en la KB y algunos dominios enumerados, y se crean variables de esos tipos en el objeto, así como se agregan líneas de código de ejemplo para ayudar a configurar estas propiedades. Así, el desarrollador solamente deberá configurar los valores de las propiedades, y no necesitará crear dominios, ni variables, ni SDTs. Solamente tendrá que utilizarlos. 395
Aquí se muestran los tres SDTs que se importan automáticamente en la KB al utilizar en algún objeto web un control QueryViewer. También se muestran los dominios enumerados que se agregan, y los valores de algunos de ellos. 396
Aquí vemos otro ejemplo, donde podemos configurar tanto estática, como dinámicamente la salida gráfica. 397
398