none
Agrupar resultados por rango de fechas

    Question

  • Buenos días. Me han encargado la siguiente consulta y la verdad no se como encararlo, tal vez me puedan ayudar...

    Tengo una tabla que registra tickets en la cual hay un campo FECHA_DE_CREACION, HORAS (total de horas dedicadas en el tratamiento del ticket), TIPO_TICKET. Con esos dato tendria que desarrollar una consulta que entregue los datos en un formato parecido a esto:

    Fecha

    Horas Totales

    Tipo Ticket

    21/01/2012 - 20/02/2012

    7

    Desarrollo

    21/02/2012 - 20/03/2012

    8,5

    Soporte

    21/03/2012 - 20/04/2012

    12

    Otros

    La sumatoria de las horas y el group by por tipo de ticket se me ocurren. Pero como hago para agrupar de por fecha de esa manera?

    Thursday, March 14, 2013 1:02 PM

Answers

  • Trata usando una expresion CASE para controlar los grupo de fechas.

    select
        case
        when fecha_de_creacion >= '20120121' and fecha_de_creacion < '20120221' then '21/01/2012 - 20/02/2012'
        ...
        when fecha_de_creacion >= '20120321' and fecha_de_creacion < '20120421' then '21/03/2012 - 20/04/2012'
        end,
        tipo_ticket,
        sum(horas) as [horas totales]
    from
        T
    where
        fecha_de_creacion >= '201221' and fecha_de_cracion < '20120421'
    group by
        case
        when fecha_de_creacion >= '20120121' and fecha_de_creacion < '20120221' then '21/01/2012 - 20/02/2012'
        ...
        when fecha_de_creacion >= '20120321' and fecha_de_creacion < '20120421' then '21/03/2012 - 20/04/2012'
        end,
        tipo_ticket;
    GO

    Si no deseas usar valores constantes en tu query, entonces tendremos que cambiar la idea un poquito.    
       


    AMB

    Some guidelines for posting questions...

    • Marked as answer by DaviT Cba Friday, March 15, 2013 7:34 PM
    Thursday, March 14, 2013 1:38 PM

All replies

  • Trata usando una expresion CASE para controlar los grupo de fechas.

    select
        case
        when fecha_de_creacion >= '20120121' and fecha_de_creacion < '20120221' then '21/01/2012 - 20/02/2012'
        ...
        when fecha_de_creacion >= '20120321' and fecha_de_creacion < '20120421' then '21/03/2012 - 20/04/2012'
        end,
        tipo_ticket,
        sum(horas) as [horas totales]
    from
        T
    where
        fecha_de_creacion >= '201221' and fecha_de_cracion < '20120421'
    group by
        case
        when fecha_de_creacion >= '20120121' and fecha_de_creacion < '20120221' then '21/01/2012 - 20/02/2012'
        ...
        when fecha_de_creacion >= '20120321' and fecha_de_creacion < '20120421' then '21/03/2012 - 20/04/2012'
        end,
        tipo_ticket;
    GO

    Si no deseas usar valores constantes en tu query, entonces tendremos que cambiar la idea un poquito.    
       


    AMB

    Some guidelines for posting questions...

    • Marked as answer by DaviT Cba Friday, March 15, 2013 7:34 PM
    Thursday, March 14, 2013 1:38 PM
  • Gracias Hunchback!! lo voy a implementar, pero sería de forma provisoria....los rangos de fecha tendrían que ser dinamicos, se te ocurre como sería?
    Thursday, March 14, 2013 1:49 PM
  • Cual es la version de SQL Server que usas?


    AMB

    Some guidelines for posting questions...

    Thursday, March 14, 2013 1:58 PM
  • SQL server 2005, me gustaria implementarla despues en un 2008 tambien...
    Thursday, March 14, 2013 2:03 PM
  • El problema esta en el valor que asignas al grupo, por ejemplo '21/01/2012 - 20/02/2012', que pudieran ser la minima y maxima fecha del grupo pero tu data no contiene todas fechas posibles necesariamente.

    La idea seria hacer un producto cartesiano entre los diferentes tickets y los grupos de fecha en el intervalo de busqueda. Luego unir este resultado con tu tabla para hacer la agregacion.

    Algo asi como:

    SET NOCOUNT ON;
    USE tempdb;
    GO
    CREATE FUNCTION dbo.GetNums(@n AS BIGINT) RETURNS TABLE
    AS
    RETURN
      WITH
      L0   AS(SELECT 1 AS c UNION ALL SELECT 1),
      L1   AS(SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
      L2   AS(SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
      L3   AS(SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
      L4   AS(SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
      L5   AS(SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
      Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
      SELECT TOP (@n) n FROM Nums ORDER BY n;
    GO
    DECLARE @sdt date = '20120121', @edt date = '20120420';
    DECLARE @T TABLE (dt date NOT NULL PRIMARY KEY);
    DECLARE @S TABLE (Ticket varchar(25) NOT NULL UNIQUE);
    
    INSERT INTO @S (Ticket) VALUES ('Desarrollo'), ('Soporte'), ('Otros');
    
    INSERT INTO @T (dt)
    SELECT
    	DATEADD([day], T.n - 1, @sdt) AS dt
    FROM
    	dbo.GetNums(DATEDIFF([day], @sdt, @edt) + 1) AS T;
    
    SELECT
    	*
    FROM
    	(
    	SELECT
    		C.grp,
    		MIN(A.dt) AS min_dt, 
    		MAX(A.dt) AS max_dt
    	FROM
    		@T AS A
    		CROSS APPLY
    		(
    		SELECT MAX(B.dt) AS grp
    		FROM @T AS B
    		WHERE B.dt <= A.dt AND DAY(B.dt) = 21
    		) AS C
    	GROUP BY
    		C.grp
    	) AS V
    	CROSS JOIN
    	@S;
    GO
    DROP FUNCTION dbo.GetNums;
    GO
    /*
    
    grp	min_dt	max_dt	Ticket
    2012-01-21	2012-01-21	2012-02-20	Desarrollo
    2012-01-21	2012-01-21	2012-02-20	Otros
    2012-01-21	2012-01-21	2012-02-20	Soporte
    2012-02-21	2012-02-21	2012-03-20	Desarrollo
    2012-02-21	2012-02-21	2012-03-20	Otros
    2012-02-21	2012-02-21	2012-03-20	Soporte
    2012-03-21	2012-03-21	2012-04-20	Desarrollo
    2012-03-21	2012-03-21	2012-04-20	Otros
    2012-03-21	2012-03-21	2012-04-20	Soporte
    
    */

    Ahora podemos unir este resultado, llamemosle R, con tu tabla original.

    select
        convert(char(10), R.min_dt, 103) + ' - ' convert(char(10), R.max_dt, 103) as fecha, 
       R.Ticket as [tipo ticket],
        sum(T.horas) as [horas totales]
    from
        R left outer join T on T.Ticket = R.Ticket and T.Fecha between R.min_dt and R.max_dt
    group by
        R.grp, R.min_dt, R.max_dt, R.ticket;
    GO

    Si posteas data de ejemplo en forma de sentencias INSERT, entonces podemos hacer una prueba.


    AMB

    Some guidelines for posting questions...

    Friday, March 15, 2013 4:00 PM
  • guau!!! no pense que fuera tan complejo el tema....me parece que voy a ingresar los rangos manualmente por unos 5 años que es mas de lo que van a utilizar el informe...muchas gracias por la ayuda Hunchback!!
    Hunchback
    Hunchback
    Hunchback
    Hunchback
    Hunchback
    Friday, March 15, 2013 7:05 PM
  • Hola,

    Proba con esta sentencia:

    SELECT T.TIPO_TICKET,(SELECT MIN(FECHA_DE_CREACION) FROM mitabla WHERE mitabla.TIPO_TICKET=T.TIPO_TICKET) AS DESDE,(SELECT MAX(FECHA_DE_CREACION) FROM mitabla WHERE mitabla.TIPO_TICKET=T.TIPO_TICKET) AS HASTA FROM mitabla AS T GROUP BY TIPO_TICKET ORDER BY TIPO_TICKET


    Victor Koch

    Friday, March 15, 2013 8:34 PM