Utilización de plantillas HTML en Documentos analíticos

Podemos ahorrar mucho tiempo en la elaboración de los Documentos analíticos utilizando plantillas de HTML predefinidas. Dichas plantillas pueden contener la estructura básica del informe, con el logo de la empresa, archivos de hojas de estilo o librerías de JavaScript.

Otra de las ventajas de utilizar plantillas, es que si queremos realizar algún cambio de diseño que afecte a los Documentos analíticos que hemos creado, realizando los cambios en la plantilla afectará a todos los documentos que la utilicen y no será necesario que pasemos documento por documento a realizar las correcciones

Creación de la plantilla
Para crear la plantilla, pulsaremos el botón Nuevo en la sección Plantillas HTML del grupo Entorno de la pestaña Proyecto, y asignaremos el nombre y la descripción tal como haríamos con cualquier otro elemento de Atlas SBI.

En la sección Diseño HTML crearemos la estructura HTML que queramos que tenga nuestro documento, recordando, eso sí, que ha de tener el <form> </form> como aparece en el diseño de los Documentos Analíticos que creamos tradicionalmente.

Por supuesto, podemos añadir imágenes o archivos css o JavaScript que hayamos cargado previamente como Recursos de Atlas SBI

Definicion Plantillas Atlas SBI

Una vez tengamos nuestra estructura básica, en los lugares donde queramos añadir nuestros controles, arrastraremos un Elemento HTML tipo PlaceHolder (ver imagen) y le asignaremos un nombre.

Podemos añadir tantos como necesitemos y todos han de estar dentro de las etiquetas <form> </form>.

Utilización de la plantilla
Para utilizar la plantilla en un documento analítico, simplemente deberemos elegir la plantilla a utilizar en el combo Plantilla HTML del documento.

Utilización de plantillas en Documentos Analíticos de Atlas SBI


Seguidamente borraremos el contenido del documento HTML y desde la pestaña Elementos HTML, arrastramos TODOS los elementos Content definidos, que corresponderán a cada uno de los elementos PlaceHolder que definimos en la nuestra plantilla.

Finalmente, dentro de cada una de las etiquetas Content podemos añadir controles o código HTML a nuestra elección.

Más información »

Convertir entero en hh:mm:ss

Cuando se trata de medir tiempo, por ejemplo el tiempo que se tarda en resolver una incidencia, o el tiempo que se tarda en contestar una llamada, por regla general los valores se guardan en segundos.

De la misma manera, calculamos la diferencia entre dos horas, el resultado lo obtendremos en segundos. 

Sin embargo, en muchos casos, nos encontraremos ante la necesidad de mostrar un número entero en segundos con un formato tipo  'hh:mm:ss' 

Para lograrlo recurriremos a la función DateAdd, aunque también es posible obtener el mismo resultado con la función Cast.

Mediante DateAdd
La finalidad de esta función de SQL Server es la de añadir un intervalo de tiempo a un valor con formato fecha. Aunque también nos permite generar a partir de un valor numérico (int) un valor de tipo fecha (date), y puede resultar de gran utilidad en escenarios donde necesitamos generar datos aleatorios en ese formato.

La sintaxis de la función es la siguiente:

DATEADD (datepart , number , date )

Siendo datepart (yyyy, m, d, h, s...) la parte de la fecha (date) donde se agregará el valor numérico entero (number).

A continuación mostraremos un ejemplo donde sumaremos y restaremos 30 segundos a una fecha indicada y a otra sin especificar.



Mediante Cast

Aunque la función DateAdd nos facilitó la conversión que necesitábamos, también es posible obtener el mismo resultado mediante la función Cast, cuya sintaxis es la siguiente:

CAST (expression AS data_type [ (length) ])

Siendo expression cualquier expresión válida, data_type el tipo de datos de destino, y length un número entero opcional que especifica la longitud del tipo de datos de destino (el valor predeterminado es 30).

En el siguiente código podréis comprobar el uso de la función Cast junto a la función DateAdd. Para la primera fue necesario un cálculo previo.




Seguramente tendréis alternativas a este tipo de conversión. Desde aquí os animamos a que las compartáis con todos nosotros.


Podéis encontrar más información en:


Más información »

Obtener la MODA de un grupo

En el desarrollo de nuestro último proyecto nos hemos encontrado ante la necesidad de saber para cada día del mes a qué hora ha habido el mayor número de llamadas, o lo que es lo mismo, cuál es la hora punta de llamadas de cada día.

En el fondo, si lo tratàramos como una muestra estadística sería obtener que hora es la Moda para cada día.

Supongamos que tenemos la siguiente consulta:
Select DiaLlamada, HoraLlamada, Count(*) as Total
From Llamadas
Where EjercicioLlamada = 2016 and MesLlamada = 9
Group by DiaLlamada, HoraLlamada
Order by 1, 3 desc

El resultado es el número total de llamadas por día y hora ordenado por día y número de llamada. Es decir, para cada bloque de días, el primer valor siempre nos devuelve la hora en la que hubo mayor número de llamadas.

Como lo que queremos es el primer registro de cada una de las categorías, no nos sirve añadir una clausula tipo TOP a la sentencia anterior, puesto que nos devolvería los n primeros resultados que serían siempre del mismo día.

Si hubieramos ordenado por número de llamadas independientemente del día tampoco podríamos utilizar la clausula TOP puesto que podrían haber registros del mismo día (si el mismo día hubiera habido muchas llamadas a varias horas) 

Solución
Para obtener el primer registro de cada una de las categorías de nuestra consulta tenemos que usar la función de categorización ROW_NUMBEREsta función devuelve el número secuencial de una fila dentro de una partición de un conjunto de resultados, comenzando con 1 para la primera fila de cada partición.

En otras palabras, numera las filas reiniciando el contador cada vez que encuentra una nueva categoría. En nuestro caso la agrupación la haremos sobre el campo DiaLlamada. Como la consulta se ordena por el campo Total, la hora que tenga más llamadas tendrá el número 1, la siguiente el 2 y así sucesivamente hasta la hora que menos llamadas haya tenido.

Por lo tanto, añadiendo la función Row_number a nuestra consulta:

Select DiaLlamada, HoraLlamada, count(*) as NumLlamadas, 
ROW_NUMBER() OVER (PARTITION BY DiaLlamada ORDER BY count(*) DESC) AS RN 
From Llamadas 
Where EjercicioLlamada = 2016 and MesLlamada = 9 
Group by DiaLlamada, HoraLlamada

Tendremos la lista ordenada y en el campo RN el número de orden dentro de la categoría, por lo que únicamente nos quedará seleccionar de esta lista los elementos que tengan el valor 1 en el campo RN.

With Lista AS
(
   Select DiaLlamada, HoraLlamada, count(*) as NumLlamadas,
ROW_NUMBER() OVER (PARTITION BY DiaLlamada ORDER BY count(*) DESC) AS RN
   From Llamadas
   Where EjercicioLlamada = 2016 and MesLlamada = 9   
   Group by DiaLlamada, HoraLlamada
)
Select * 
FROM Lista
Where RN = 1;



Es posible que dos franjas horarias tengan el mismo número de llamadas. En nuestro caso no importaba cual de ellas obtener. Si fuese importante, se debería modificar la consulta para ordenar según el criterio necesario.

Otras funciones de categorización

Además de Row_number, existen otras alternativas para ordenar y categorizar resultados, os dejamos la definición y un ejemplo de utilización de cada una de ellas.

ROW_NUMBER es una función de categoría y como tal, es una función no determinista. Si la expresión de ordenación no es única, cada vez que se ejecute la consulta podrá asignar posiciones diferentes para cualquier fila donde la expresión de ordenación sea la misma. En cambio, si esa expresión de ordenación es única, cada fila obtendrá una número de fila única.

RANK - A diferencia de ROW_NUMBER, no asigna una numeración única cuando dos registros comparten la misma posición. Es decir, podrán haber tantas posiciones 1ª, 2ª,... como registros compartan esa posición.

DENSE_RANK - Su funcionamiento es similar a RANK, aunque a diferencia de ese, sí asigna números contiguos.

NTILE - Según el parámetro que le asignemos dividirá los registros en tantos grupos, repitiendo la numeración.

Podéis comprobar sus diferencias en el resultado de la consulta que hemos estado utilizando:



Podéis obtener más información en los siguientes enlaces:

Funciones de categoría (Transact-SQL)
ROW_NUMBER (Transact-SQL)
ROW_NUMBER, o cómo obtener la enésima fila de un conjunto de resultados
Get top 1 row of each group
Adding Row Number to SQL SELECT result
Más información »

Cómo guardar parámetros seleccionados por el usuario

En la mayoría de los documentos analíticos de Atlas SBI es posible filtrar la información contenida a través de una selección realizada en un panel de selectores situados en alguna zona del documento. Por lo general, ese panel de selectores muestra, inicialmente, valores genéricos o por defecto cada vez que se abre. A partir de ahí, el usuario puede escoger los valores de los selectores que considere oportunos y que modificarán la información mostrada por el documento analítico.



Cabe la posibilidad de que el usuario de un documento analítico seleccione siempre las mismas opciones que le proporcionan los selectores, de modo que acabe realizando una tarea repetitiva y automática. Ante ese posible escenario, hemos creído oportuno mostrar una solución de fácil implementación cuyos detalles se muestran a continuación.

Mediante la siguiente solución, un usuario podrá guardar los valores que desee de un panel de selectores. Así, cuando vuelva a cargar el documento, los selectores mostrarán por defecto las selecciones guardadas, y la información aparecerá ya filtrada por esa selección. Todo ello, manteniendo la capacidad de escoger cualquier otra opción disponible de los selectores.

Visión general
La solución consiste en guardar los valores que el usuario quiera que aparezcan como filtros del documento analítico consultado en una tabla de nuestra base de datos. Para llevarlo a cabo, serán necesarios:

  • dos nuevos controles en el documento: un button y un simpledata, 
  • una nueva tabla en la base de datos, 
  • un procedimiento almacenado y 
  • la modificación de los selectores originales.

El button lo podremos colocar en la zona de los selectores para que el usuario tenga la posibilidad de guardar su selección si lo estima oportuno. Al ejecutarlo, le pasará los valores necesarios al SimpleData para que llame un procedimiento almacenado en nuestra base de datos que poblará la nueva tabla.

Dicha tabla deberá contener los valores necesarios para devolverlos al selector original; a saber, nombres de proyecto, documento, rol, usuario y control. De manera que la próxima vez que se abra el documento, los selectores consultarán dicha tabla para mostrar, si es que existe tal registro, la selección guardada por el usuario.


Solución completa

Se puede descargar la solución completa desde aquí, los archivos adjuntos contienen:

  1. BD-Parametros - Script de SQLServer para generar una Base de datos de ejemplo que incluye la tabla donde se almacenarán los datos a guardar de los selectores y el procedimiento almacenado para actualizarla.
  2. ProcedimientoAlmacenado - Selectores - Procedimiento almacenado de SQLServer por separado.
  3. GuardarParametros.gz - Archivo backup de Atlas SBI donde se incluyen:
    • PasoParametros-01 - Documento de ejemplo con dos selectores para comprobar la modificación de los selectores
    • PasoParametros-02 - Documento de ejemplo con tres selectores para comprobar la modificación de los selectores
Si se desea comprobar directamente el funcionamiento, será necesario realizar lo siguiente:
  • Ejecutar el script del archivo BD-Parametros para generar la BD.
  • Importar en AtlasSBI cualquiera de los documentos contenidos en el archivo GuardarParametros.gz y asignarlos a un rol. 
Las consultas contenidas en los dos documentos trabajan sobre la base de datos Northwind. Si no se dispone de ella, habrá que modificarlas.

Procedimiento detallado
Aún así, los siguientes pasos explican la manera de implementar esta solución. Están desarrollados en SQL Server, pero son perfectamente extrapolables a cualquier otro sistema:

  • Paso 1: Crear una tabla en la BD para almacenar los datos que el usuario desee guardar por defecto. En esa tabla se guardarán los nombres del ProyectoDocumentoRolUsuarioControl y el Valor seleccionados. (El archivo adjunto "BD-Parametros" contiene un script para la generación de una BD a modo de ejemplo de uso)

  • Paso 2: Crear un nuevo control de tipo Button en el documento donde se encuentren los selectores que queramos capturar. Ese botón recibirá por parámetros los valores de los selectores. (Ejemplos disponibles en los documentos "Guardar parámetros - Doc 1 y 2" dentro del archivo adjunto de backup de Atlas SBI "GuardarParametros.gz" 
     
    • Paso 3: Modificar, en el documento donde se haya añadido el control Button, cada uno de los selectores para que muestren el valor correspondiente guardado en la tabla del paso 1, o bien la lista de selección normal si aún no hubiera selección guardada. Se pueden comprobar ejemplos en los selectores: Vendedor, Producto y País, de los documentos contenidos en el archivo "GuardarParametros.gz".
    • Paso 4: Crear un Procedimiento almacenado en la BD que actualizará la tabla de parámetros cuando sea activado el control de tipo Button del paso 2. Este procedimiento se encargará de recoger los valores de cada control a guardar, comparándolos con los existentes en la tabla del paso 1 y añadiéndolos en caso de no existir previos o bien haber sido modificados por la nueva selección. (Archivo adjunto: "ProcedimientoAlmacenado - Selectores")
    • Paso 5: Crear un control Simple Data y añadirlo al documento (No es necesario que este control sea visible, pero sí es indispensable añadirlo). Se encargará de recoger los valores capturados por el botón y ejecutar la llamada al Procedimiento almacenado anterior con los valores a guardar en la tabla del paso 1.​​ 

    Una vez implementada la solución, al abrir el documento, en lugar de aparecer la selección por defecto:




    Se realizará una consulta a la tabla para comprobar si existen valores guardados:



    ​​
    Y, en caso de haberlos, cargará esos valores directamente en los selectores.

    No es necesario seleccionar un valor para cada selector. Es posible incluso guardar el valor por defecto, como en el caso del ejemplo, el valor "-Todos-" y combinarlo con cualquier otro valor de los selectores.


    Más información »

    Conectar Atlas SBI a BigQuery mediante Driver ODBC Simba

    El volumen de datos generados por las diferentes aplicaciones de gestión, así como por los sistemas que nos relacionan con nuestros clientes, competidores, proveedores, etc. crece de forma exponencial.

    El conjunto de tecnologías conocidas como Big Data nace para gestionar este gran volumen de información. Como en todos los sectores, y sobre todo cuando se trata de tecnologías incipientes, hay multitud de soluciones que van desde la instalación en nuestras dependencias a utilizar sistemas en Cloud.

    En este sentido, Google ofrece BigQuery como alternativa al procesamiento de grandes volúmenes de datos sin necesidad de instalar infraestructura en nuestras dependencias. Esta tecnología permite realizar consultas que con los sistemas tradicionales podrían tardar minutos e incluso horas en apenas unos segundos.


    Al final del artículo encontraréis más información sobre qué es y cómo comenzar a trabajar con Google BigQuery.

    Por supuesto, no es la única tecnología válida ni el único fabricante que ofrece algo parecido, se podría hacer exactamente lo mismo con Amazon DynamoDB, Mongo DB cualquier otro sistema de Big Data.

    Configuración del driver de Big Query

    Para conectarnos en tiempo real a BigQuery utilizaremos el Driver ODBC para BigQuery de Simba. Una vez descargado, las claves de activación para la versión real o trial las recibiremos por separado y deberemos copiarlas en la carpeta de Simba. Cuando lo hayamos instalado, procederemos a la creación de un DSN.

    Desde el Panel de control de Windows, crearemos un nuevo DSN de sistema del tipo Simba ODBC Driver with SQL Connector for Google BigQuery. Asignaremos como nombre "Google BigQuery"

    Asignaremos un nombre y pulsaremos el botón Sign In.


    Aparecerá una pantalla para conectar con nuestro servicio de Google BiqQuery, deberemos introducir nuestro usuario de Google y la contraseña


    Una vez identificados, nos solicitará permiso para acceder a las consultas y administración de datos de Big Query.



    Cuando aceptemos la petición, nos devolverá una clave que deberemos insertar en la configuración del driver ODBC. Para ello la copiaremos en el portapapeles (e incluso en algún lugar seguro).



    Y la pegaremos en el campo Confirmation Code. El campo Refresh Token se actualizará con la validación por parte de Google.



    Para realizar las pruebas elegiremos una de las bases de datos públicas que proporciona Google, pero podemos indicar nuestra base de datos (Catalog) y nuestro proyecto en los desplegables.



    Antes de guardar el DSN provaremos la conexión.


    Configuración de la conexión a BigQuery en Atlas SBI

    Para configurar la conexión en Atlas SBI, abriremos nuestro proyecto, seleccionaremos la pestaña Conexiones y crearemos una nueva conexión.

    Seleccionaremos ODBC como Proveedor de conexión, y el la cadena de conexión escribiremos "DSN=Google BigQuery" (o el nombre que hayamos indicado en nuestra conexión ODBC)



    Probaremos la conexión


    Y ya podremos utilizarla en cualquier control de Atlas SBI para obtener datos en tiempo real de Big Data.

    Como podéis apreciar en la imagen, Atlas SBI muestra el esquema de la base de datos BigQuery, tanto tablas como campos y tipos de datos para facilitar la creación de consultas.


    En los ejemplos utilizados hemos realizado consultas sobre bases de datos de 137 Millones de registros.




    Enlaces relacionados



    Más información »

    Consultar el catálogo de Bases de datos en SQL Server

    De la misma manera que en ocasiones necesitamos información sobre las tablas de una base de datos, podemos encontrarnos ante la necesidad de conocer qué bases de datos se hallan en una instancia de SQL Server y sus características, ya sea para su administración ulterior o como una simple consulta de estado.

    No es necesario especificar el uso de la base de datos master. Se pueden ejecutar desde cualquier base de datos contenida en la instancia.

    Ver los archivos de las Bases de datos

    La siguiente consulta nos permitirá listar todos los archivos de las bases de datos contenidas en una instancia. Es decir, devolverá una fila por cada base de datos almacenada en la base de datos master. Además, nos permitirá conocer la ubicación física de cada una de las bases de datos, así como su tamaño y estado.


    SELECT * FROM sys.master_files




    Obtener una lista de las Bases de datos

    Mediante la siguiente consulta obtendremos un listado de todas las bases de datos contenidas en nuestra instancia, con sus respectivos nombres, identificadores, fechas de creación y demás características.

    SELECT * FROM sys.databases



    Ubicaciones de los archivos de las Bases de datos

    Podemos utilizar esta última consulta para averiguar las ubicaciones de los archivos de las bases de datos contenidas en nuestra instancia. Nos devolverá una fila por cada base de datos y las ubicaciones de los archivos de datos y registros, así como la fecha de creación de la base de datos.

    SELECT db.name, db.database_id, db.create_date,
       dt.physical_name AS data_physical_name, dt.data_space_id AS data_data_space_id,
       lg.physical_name AS log_physical_name, lg.data_space_id AS log_data_space_id
    FROM sys.databases db
       LEFT JOIN sys.master_files dt ON db.database_id = dt.database_id AND dt.type_desc = 'ROWS'
       LEFT JOIN sys.master_files lg ON db.database_id = lg.database_id AND lg.type_desc = 'LOG'
     






    Podréis encontrar más información en:

    https://www.datavail.com/blog/use-sys-master_files-sql-servers/
    https://www.mssqltips.com/sqlservertip/1037/system-information-in-sql-server-2000-vs-sql-server-2005/
    http://www.sqlservercentral.com/Forums/Topic932220-146-1.aspx


    Más información »

    Consultar definición de las tablas de una Base de datos

    Si alguna vez habéis realizado la documentación de un proyecto sabréis el tiempo que puede llegar a consumir documentar cada una de las tablas. Una manera de reducirlo podrá ser mediante el uso de las consultas contenidas en este artículo, ya que con ellas podremos obtener, de manera rápida, completa y eficaz, información agrupada sobre nuestras bases de datos.

    El resultado de cada consulta dependerá de la base de datos a la que realice la solicitud dentro de una instancia de SQL Para este artículo, utilizaremos la conocida base de datos pública Northwind, por lo que los resultados se referirán a ella. Antes de realizar la correspondiente consulta, tendremos que seleccionar la base de datos en el selector de base de datos disponibles, o bien escribir antes de la consulta: "USE Northwind", pudiendo cambiar "Northwind" por el nombre de vuestra base de datos.

    Las consultas que a continuación detallaremos nos ofrecerán la siguiente información:
    1. Listado de las tablas de la base de datos
    2. Definiciones de columnas de todas las tablas
    3. Toda la información de todas las columnas
    4. Nombre de tablas e información sobre filas y espacio ocupado

    Listado de las tablas de la base de datos

    La primera consulta nos proporcionará un listado completo de las tablas de la base de datos.

    El resultado nos dará el nombre de la BBDD ("northwind"), el nombre del esquema que contiene la tabla ("dbo"), el nombre de la tabla (TABLE_NAME) y el tipo de tabla (TABLE_TYPE).


    SELECT * FROM Information_schema.tables



    Si quisiéramos tener un listado únicamente de las tablas o de las vistas añadiríamos la cláusula WHERE correspondiente:

    WHERE TABLE_TYPE = 'BASE TABLE'o
    WHERE TABLE_TYPE = 'VIEW'


    Definiciones de columnas de todas las tablas

    Para obtener la definición de las columnas de todas las tablas, es decir, el esquema de la tabla, el nombre de la tabla, la posición ordinal, el nombre de la columna, el tipo de dato contenido y su longitud máxima; utilizaremos la siguiente consulta:

    SELECT Table_schema, Table_Name, Ordinal_Position, Column_name, Data_Type,
    Character_maximum_length as Max_length
    FROM Information_schema.columns


    Toda la información de todas las columnas

    A diferencia de la consulta anterior, ésta devuelve no sólo la definición, sino toda la información disponible de todas las columnas.

    SELECT * FROM INFORMATION_SCHEMA.columns



    Nombre de tablas e información sobre filas y espacio ocupado

    Ésta consulta nos facilitará los nombre e información relativa a las filas y el espacio ocupado. En concreto, nos devolverá los siguientes campos:


    • TableName: Nombre de cada tabla de la BBDD
    • IndexName: Clave primaria asignada
    • Rows: Número de filas
    • TotalPages: Número total de páginas asignadas o reservadas por esta unidad de asignación
    • UsedPages: Número total de páginas actualmente en uso
    • DataPages: Número de páginas usadas que tienen datos de fila, datos LOB y datos de desbordamiento de fila. Se omiten las páginas de índice internas y páginas de administración de asignación.
    • TotalSpaceMB, UsedSpaceMB y DataSpaceMB: Espacio en MB ocupado por las anteriores páginas.


    SELECT
        t.NAME AS TableName,
        i.name AS indexName,
        p.[Rows],
        sum(a.total_pages) AS TotalPages,
        sum(a.used_pages) AS UsedPages,
        sum(a.data_pages) AS DataPages,
        (sum(a.total_pages) * 8) / 1024 AS TotalSpaceMB,
        (sum(a.used_pages) * 8) / 1024 AS UsedSpaceMB,
        (sum(a.data_pages) * 8) / 1024 AS DataSpaceMB
    FROM
        sys.tables t INNER JOIN     
        sys.indexes i ON t.OBJECT_ID = i.object_id INNER JOIN
        sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id INNER JOIN
        sys.allocation_units a ON p.partition_id = a.container_id
    WHERE
        t.NAME NOT LIKE 'dt%' AND i.OBJECT_ID > 255 AND i.index_id <= 1
    GROUP BY
        t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
    ORDER BY
        object_name(i.object_id)






    Podéis obtener más información en los siguientes enlaces:

    https://www.mssqltips.com/sqlservertutorial/179/sql-server-informationschema-views-tutorial/
    https://msdn.microsoft.com/es-es/library/ms189792.aspx

    Más información »

    Error 0x858c001b al instalar SQL Server

    En la última instalación de Atlas SBI me he encontrado con el error 0x858c001b al instalar SQL Server.

    En concreto:



    SQL Server Setup has encountered the following error:

    The SQL Server license agreement cannot be located for the selected edition, <EDITION>
    . This could be a result of corrupted media or the edition being unsupported by the media.

    Error code 0x858C001B.
    El error se produce para cualquier versión (2012, 2014) y edición (Standard, Express,...) y es debido a que el idioma de Windows Server ha de coincidir con el idioma del SQL Server, en mi caso estaba instalando SQL Server ESN (Español) sobre un Windows Server en ENU (Inglés).

    Parece ser que el error se produce incluso si las versiones de idioma y formatos de fecha no son exactamente iguales como podría pasar si se instala la versión española sobre un server con configuración de latinoamerica.

    Más información en los links:
    Más información »

    Selección de actividades entre dos fechas

    Uno de los criterios de selección que los usuarios suelen pedir con más frecuencia es poder analizar lo ocurrido entre dos fechas.

    En aquellos Hechos que se producen en una fecha concreta, como por ejemplo, las facturas, las visitas a una página web, etc. La fórmula de selección es fácil y únicamente se ha de mirar si la fecha del Hecho está entre las fechas de inicio y de fin del periodo.

    En otras palabras, suponiendo que la fechas de inicio y fin del periodo a evaluar se guarden en las variables FIniPeriodo y FFinPeriodo respectivamente, y la fecha del hecho se guarde en el campo FechaHecho, la fórmula de selección quedaría:

    FIniPeriodo >= FechaHecho and FechaHecho <= FFinPeriodo

    Actividades entre dos fechas
    El tema se complica cuando queremos seleccionar las actividades abiertas entre dos fechas. Es decir, lo que queremos analizar son hechos que no se producen en un instante, sino que tienen lugar durante un periodo de tiempo. Por ejemplo, queremos analizar proyectos, expedientes, actividades de servicio, etc.

    En este caso, hemos de tener en cuenta que la actividad tendrá dos fechas, la Fecha de Inicio de la Actividad (FIniActiv) y la Fecha de Fin de la Actividad (FFinActiv)

    Lo primero que debemos tener claro es las variantes posibles entre fechas de inicio y fin de actividad y fechas de inicio y fin de periodo. La siguiente imagen nos muestra todas las posibilidades.

    Esquema de actividades dentro de un periodo de tiempo

    En concreto son:
    1. Que la actividad empiece antes de inicio del periodo y acabe dentro del periodo
    2. Que la actividad empiecen entre el periodo y acabe después
    3. Que la actividad empiece y acabe dentro del periodo
    4. Que la actividad empiece antes del periodo y acabe después
    5. Que la actividad empiece y acabe antes del periodo
    6. Que la actividad empiece y acabe después del periodo.
    De todas estas, las que nuestro informe debe tratar son las 4 primeras (las que en la imagen están en verde).

    El primer impulso para definir la condición que incluya los cinco casos que nos interesan, sería empezar a definir las condiciones que han de cumplir cada una de las posibilidades y unirlas mediante un or.

    Sin embargo, existe una forma más fácil y limpia de hacerlo, y es concentrarnos en las que NO están dentro del periodo (las que no queremos analizar).

    De esta manera, la fórmula que selecciona todas las actividades que están fuera del periodo es:

    FFinActi < FIniPeriodo or FIniAct > FFinPeriodo

    Una vez tenemos la condición, para obtener las actividades que SÍ están dentro del periodo, solamente tenemos que negar la condición.

    Para ello, echaremos mano del algebra de Boole y en concreto de las leyes de Morgan que nos dicen que "la negación de las conjunción es la disyunción de las negaciones" y "la negación de la disyunción es la conjunción de las negaciones" o lo que se conoce como: No (A y B) es lo mismo que (No A) o (No B) -para la negación de la conjunción- No (A o B) es lo mismo que (No A) y (No B).

    De esta manera, negando la condición que selecciona lo que queda fuera del periodo tendremos la condición que selecciona todas las actividades que quedan de alguna manera dentro del periodo. 

    Por lo tanto, tendremos que:

    Not (FFinActi < FIniPeriodo or FIniAct > FFinPeriodo) 

    Aplicando la ley de Morgan


    Not (FFinActi < FIniPeriodo) and Not (FIniAct > FFinPeriodo)

    Finalmente, resolviendo cada una de las condiciones tendremos que la condición que selecciona las actividades que están dentro del periodo es:

    (FFinActi >= FIniPeriodo) and  (FIniAct <= FFinPeriodo)






    Más información »

    Lo más visto