[英]SQL Server query for total number of days for a month between date ranges
[英]SQL: How to count the number of unique days between date ranges that may overlap?
我有一個棘手的問題。 我有一個如下的社會保障繳款表( 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-Define日期范圍,這是一個時間窗,用於計算人們的貢獻。 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
請嘗試以下方法。 您首先需要創建一個數字函數。
create FUNCTION [dbo].[NumberTable] (@Min int, @Max int)
RETURNS @T TABLE (Number int NOT NULL PRIMARY KEY)
AS
BEGIN
INSERT @T VALUES (@Min)
WHILE @@ROWCOUNT > 0
BEGIN
INSERT @T
SELECT t.Number + (x.MaxNumber - @Min + 1)
FROM @T t
CROSS JOIN (SELECT MaxNumber = MAX(Number) FROM @T) x --Current max
WHERE
t.Number <= @Max - (x.MaxNumber - @Min + 1)
END
RETURN
END
然后,我正在做的是循環工作,獲取日期和值的日期,並在其間插入所有日期。
Declare @Dates table
(UserId int,
DayDate datetime
)
create table #aux(id int identity(1,1),
Idpersona int
,FechaIngreso datetime
,FechaEgreso datetime
)
insert into #aux values(5690180,'1987/1/1','2012/11/30')
insert into #aux values(5690180,'2010/1/1','2012/11/30')
insert into #aux values(5690180,'2012/6/11','2012/11/15')
insert into #aux values(5690180,'2012/4/12','2012/4/25')
insert into #aux values(5690180,'2012/3/16','2012/3/30')
insert into #aux values(5690180,'2011/6/18','2011/10/15')
insert into #aux values(5690180,'2012/12/20','2013/1/20')
insert into #aux values(5690180,'2012/11/21','2012/12/15')
declare @counter int
select @counter = 1
WHILE @counter <= (Select COUNT(*) from #aux)
Begin
declare @User int
select @User = Idpersona from #aux where id = @counter
declare @YearMonthDayFrom datetime
declare @YearMonthDayTo datetime
select @YearMonthDayFrom = FechaIngreso from #aux where id = @counter
select @YearMonthDayTo= FechaEgreso from #aux where id = @counter
Declare @DateDifference int
select @DateDifference = datediff(day, @YearMonthDayFrom, @YearMonthDayTo)
insert into @Dates
select @User,
dateadd(day,number, @YearMonthDayFrom)
from
dbo.NumberTable(0,@DateDifference)
select @counter = @counter + 1
end
select year(daydate) as PeriodGroup,
UserId,
COUNT(distinct DayDate)
from @Dates
group by UserId,
year(daydate)
drop table #aux
最后,我計算了不同的日子,在我的例子中,我按年分組。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.