SQL:如何计算可能重叠的日期范围之间的唯一天数?

标签 sql sql-server-2008 date

我有一个棘手的问题。我有一张社会保障缴款表,如下 ( SQL Fiddle )

    IdPersona   fecha_ingreso   fecha_egreso
5690180         01/01/1987      30/11/2012
5690180         01/01/2010      30/11/2012
5690180         11/06/2012      15/11/2012
5690180         12/04/2012      25/04/2012
5690180         16/03/2012      30/03/2012
5690180         18/06/2011      15/10/2011
5690180         20/12/2012      20/01/2013
5690180         21/11/2012      15/12/2012

每一行代表个人的一份工作。一个人可能同时从事一份以上的工作。我需要计算每个人在特定时期(例如去年)做出的贡献的天数,问题是我必须只计算不同的贡献天数,而不是为一个人计算同一天多次。我怎样才能做到这一点?


概述计算天数但不唯一的可能解决方案 1-定义日期范围,一个计算人们所做贡献的时间窗口。 2-对于每个 RespondentID,我必须计算在此期间输入窗口有多少天?

DECLARE @FchRef DATETIME

SET @FchRef ='2011-05-01'

--Fhc referencia de comienzo del programa a partir de cual calcular aportes
DECLARE @PeriRef SMALLINT

SET @PeriRef =24

--Periodo a partir de la Fch ref para contar aportes
DECLARE @FchCotDesde DATETIME

SET @FchCotDesde=Dateadd(MONTH, -24, @FchRef)

--Fch a partir de la cual calcular aportes
SELECT ut.documento                 'CI_UT',
       sum(DATEDIFF(DAY, CASE
                           WHEN CONVERT(DATETIME, act.fecha_ingreso, 103) < @FchCotDesde THEN @FchCotDesde
                           ELSE CONVERT(DATETIME, act.fecha_ingreso, 103)
                         END, CASE
                                WHEN fecha_egreso = '' THEN @FchRef
                                ELSE CONVERT(DATETIME, act.fecha_egreso, 103)
                              END)) 'DiasContados'
FROM   dbo.[UT2011_12] ut
       LEFT JOIN dbo.DatosPersonalesyDomicilios dat
         ON cast(cast(ut.documento AS DECIMAL(12, 0))AS VARCHAR) = dat.nro_documento
       LEFT JOIN dbo.Actividades act
         ON act.pers_identificador = dat.pers_identificador
            AND ( CONVERT(DATETIME, act.fecha_egreso, 103) = ''
                   OR CONVERT(DATETIME, act.fecha_egreso, 103) >= @FchCotDesde )
            -- La Fch de egreso es vacia ó con Fch posterior a fch ref
            AND CONVERT(DATETIME, act.fecha_ingreso, 103) <= @FchRef
--La Fch de inicio de act es anterior a la FchRef
WHERE  ut.UT_2011_Inscriptos = 1
        OR ut.UT_2012_Inscriptos = 1
GROUP  BY ut.documento 

此解决方案的问题在于,如果日期范围(入口和导出)重叠,它会起作用。 在我看来,这是解决问题的方法:1 - 创建一个包含每个人的游标 2 - 我创建了一个循环,在每天的窗口期循环,如果你抛出一个做出贡献和 0 但是,对于每个人个人。我提出的解决方案将如何极其复杂。你能想到更好的解决方案吗?

用这个脚本你可以创建表

        create table #aux(
        Idpersona int
        ,FechaIngreso datetime
        ,FechaEgreso  datetime
        ) 
    insert into #aux values(5690180,'1987/01/01','2012/11/30')
    insert into #aux values(5690180,'2010/01/01','2012/11/30')
    insert into #aux values(5690180,'2012/06/11','2012/11/15')
    insert into #aux values(5690180,'2012/04/12','2012/04/25')
    insert into #aux values(5690180,'2012/03/16','2012/03/30')
    insert into #aux values(5690180,'2011/06/18','2011/10/15')
    insert into #aux values(5690180,'2012/12/20','2013/01/20')
    insert into #aux values(5690180,'2012/11/21','2012/12/15')
    select * from #aux

我看问题的好方法是用一张图

111111111111111111111111111000000000000000000000000000000000000000000000000000000000
|----A1----|
         |----A2----|
               |----A3----|

00000111111111111111110000001111111111111111111111111000000000000000000000000000000
     |------B1-------|
                            |----------B2-----------|

最佳答案

可能最简单的方法是创建一个辅助日期表。

CREATE TABLE Dates(D DATE PRIMARY KEY)

/*
Load dates between 1990-01-01 and 2049-12-31*/
INSERT INTO Dates
SELECT TOP (21915) DATEADD(DAY,ROW_NUMBER() OVER (ORDER BY (SELECT 1)), '19891231')
         AS N
   FROM master..spt_values v1,
        master..spt_values v2;

然后你可以做

DECLARE @FchRef DATE = '20110501';
DECLARE @FchCotDesde DATE = DATEADD(MONTH, -24, @FchRef);

SELECT [IdPersona],
       COUNT(DISTINCT Dates.D) AS Contributions
FROM Contributions  
JOIN Dates ON Dates.D BETWEEN fecha_ingreso AND fecha_egreso
WHERE Dates.D BETWEEN DATEADD(MONTH, -24, @FchRef) AND @FchRef
GROUP BY IdPersona

关于SQL:如何计算可能重叠的日期范围之间的唯一天数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17074362/

相关文章:

MySQL - 根据周/月数字获取 sum()

mysql - SQL:查找每个运行者运行之间的平均天数

mysql - 将日期转换为 dd-mm-yy 格式并从 SQL 2008 中选取的值中选择最后 12 个日期

php - SQLite在文本字段中未正确排序日期

javascript - 更改新的日期格式

mysql - NodeJS -> 错误无法读取未定义的属性 'length'

mysql - 将 2 个查询合并为一个查询

sql-server - 从另一个数据库插入数据库,在 SQL Server 中指定一些值

sql-server - 如何从现有表中设置数据库图?

java - 如何以 'yyyy-mm-dd' 格式将日期列表放入 JComboBox 中?