none
Repetir n veces una fecha según su diferencia entre ella y otra RRS feed

  • Pregunta

  • Buenos días, 

    Se me plantea la siguiente duda,

    Al realizar una consulta con fechas, calculo los días que hay entre dos campos. Lo que pasa es que tengo que poner tantos registros como diferencia tengo y sumar un día a la fecha. Me explico con un ejemplo

    id_registro fecha1 fecha2 dif

    1 01/01/2016 05/01/2016 4

    2 05/01/2016 07/01/2016 2 ... etc

    Necesitaría mostrar lo siguiente:

    id_registro fecha1 fecha2 dif

    1 01/01/2016 05/01/2016 4

    1 02/01/2016 05/01/2016 3

    1 03/01/2016 05/01/2016 2

    1 04/01/2016 05/01/2016 1

    ... y así con todos los registros

    Por favor, me podéis ayudar??

    Gracias !!

    viernes, 7 de octubre de 2016 10:15

Respuestas

  • Una forma de resolver este problema es haciendo uso de una tabla auxiliar de números, como esta funcion tipo tabla escrita por Itzik Ben-Gan.

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE FUNCTION [dbo].[ufn_GetNums](@low AS bigint, @high AS bigint) 
    RETURNS table
    AS
    RETURN (
    WITH
    L0 AS (SELECT c FROM (VALUES(1),(1)) AS D(c)),
    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 rownum FROM L5)
    SELECT TOP(@high - @low + 1) @low + rownum - 1 AS n
    FROM Nums
    ORDER BY rownum
    );
    GO

    El resto seria usar el operador APPLY para poder pasar la diferencia entre fechas hacia la funcion y generar cuantas filas sea necesaria.

    DECLARE @T table (
    id_registro int,
    fecha1 date,
    fecha2 date
    );
    
    INSERT INTO @T
    	(id_registro, fecha1, fecha2)
    VALUES
    	(1, '20160101', '20160105'),
    	(2, '20160105', '20160107');
    
    SELECT
    	T1.id_registro,
        T1.fecha1,
        T1.fecha2,
    	DATEADD(DAY, T2.n - 1, T1.fecha1) AS fecha3,
    	T2.n - 1 AS dif
    FROM
    	@T AS T1
    	OUTER APPLY
    	dbo.ufn_GetNums(1, DATEDIFF(DAY, T1.fecha1, T1.fecha2) + 1) AS T2
    ORDER BY
    	T1.id_registro,
    	T2.n DESC;
    GO


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    viernes, 7 de octubre de 2016 12:52
  • Podrías hacer un while para que vaya recorriendo las fechas y meter el valor en una tabla temporal, y devuelves la consulta de la tabla temporal.

    EjEMPLO: 

    declare @startDate date = '20160601'

    declare @endDate date = '20160605'

    create table #temp(id int, start_date date, end_date date, diff int)

    while @startDate < @endDate

    begin

    insert into #temp select 1, @startDate, @endDate, datediff(day, @startDate, @endDate)

    select @startDate = dateadd(day, 1, @startDate)

    end

    select * from #temp

    viernes, 7 de octubre de 2016 10:38

Todas las respuestas

  • Podrías hacer un while para que vaya recorriendo las fechas y meter el valor en una tabla temporal, y devuelves la consulta de la tabla temporal.

    EjEMPLO: 

    declare @startDate date = '20160601'

    declare @endDate date = '20160605'

    create table #temp(id int, start_date date, end_date date, diff int)

    while @startDate < @endDate

    begin

    insert into #temp select 1, @startDate, @endDate, datediff(day, @startDate, @endDate)

    select @startDate = dateadd(day, 1, @startDate)

    end

    select * from #temp

    viernes, 7 de octubre de 2016 10:38
  • Pues creo que me vale. Muchas gracias Cousi :)
    viernes, 7 de octubre de 2016 11:18
  • Una forma de resolver este problema es haciendo uso de una tabla auxiliar de números, como esta funcion tipo tabla escrita por Itzik Ben-Gan.

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE FUNCTION [dbo].[ufn_GetNums](@low AS bigint, @high AS bigint) 
    RETURNS table
    AS
    RETURN (
    WITH
    L0 AS (SELECT c FROM (VALUES(1),(1)) AS D(c)),
    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 rownum FROM L5)
    SELECT TOP(@high - @low + 1) @low + rownum - 1 AS n
    FROM Nums
    ORDER BY rownum
    );
    GO

    El resto seria usar el operador APPLY para poder pasar la diferencia entre fechas hacia la funcion y generar cuantas filas sea necesaria.

    DECLARE @T table (
    id_registro int,
    fecha1 date,
    fecha2 date
    );
    
    INSERT INTO @T
    	(id_registro, fecha1, fecha2)
    VALUES
    	(1, '20160101', '20160105'),
    	(2, '20160105', '20160107');
    
    SELECT
    	T1.id_registro,
        T1.fecha1,
        T1.fecha2,
    	DATEADD(DAY, T2.n - 1, T1.fecha1) AS fecha3,
    	T2.n - 1 AS dif
    FROM
    	@T AS T1
    	OUTER APPLY
    	dbo.ufn_GetNums(1, DATEDIFF(DAY, T1.fecha1, T1.fecha2) + 1) AS T2
    ORDER BY
    	T1.id_registro,
    	T2.n DESC;
    GO


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    viernes, 7 de octubre de 2016 12:52
  • Muchas gracias por vuestra ayuda.
    lunes, 10 de octubre de 2016 10:13
  • aunque yo firmaba como brigada anti cursores, y la solución de AMB es mucho mas eficiente, creo que la tuya simplemente funciona por eso te la marco :)  Bienvenido

    Comparte lo que sepas, aprende lo que no sepas (FGG)
    portalSQL
    El rincón del DBA

    lunes, 10 de octubre de 2016 20:21
    Moderador