2013-01-21 57 views
3

这里是我正在处理的内容: 我给出了一个表(访问),其中包含以下具有示例数据的模式。按日历月计算居住时长

VISIT

VisitNo Location AdmissionDate DischargeDate LengthOfStay 
1   A   2012-04-28  2012-05-30  32 
2   A   2012-04-20  2013-05-20  90 
3   B   2012-04-01  2012-05-01  30 
4   B   2012-05-01  2012-05-03  2 
..................................................... 

的要求是,返回的数据集是在以下的结构。按日历月(YYYYMM)计算每个位置的总长度。

CalendarMonth TotalLengthOfStayEachMonth(AdmissionToDate) Location 
201204   xxx           x 
201205   yyyy           y 
201206   zzzz           z 
.........  ............... 

TotalLengthOfStayEachMonth的计算有点棘手。自录取日期(admissionToDate)以来,这些日子不计算在每月30天的基础上。例如,VISIT表中的第一条记录具有;住宿

  • 2天201204
  • 2 + 30 = 32201205天的等等...

预先感谢您的建议...仅供参考,我们有几百个一千个地点,五年的数据。

回答

1

虽然我更喜欢看到你想要的输出,也许这样的事情会帮助你开始:

SELECT 
    CONVERT(char(6), AdmissionDate, 112) as CalendarMonth , 
    SUM(DAY(DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,AdmissionDate)+1,0)))-DAY(AdmissionDate)) as TotalLengthOfStayEachMonth, 
    Location 
FROM VISIT 
GROUP BY CONVERT(char(6), AdmissionDate, 112), Location 

添加位置将有可能给你复制CalendarMonths,但我认为这是确定。

编辑 -

我这个多一点发挥各地,因为我意识到了几个月会错过日期,如果DischargeDate是大于1月满则AdmissionDate,以及与此想出了 - 它使用spt_values表:

select 
    CONVERT(char(6), AdmissionDate+v.number, 112) as CalendarMonth, 
    COUNT(*) Days, 
    Location 
from Visit t 
inner join master..spt_values v 
    on v.type='P' and v.number <= DATEDIFF(d, AdmissionDate, DischargeDate) 
group by Location, CONVERT(char(6), AdmissionDate+v.number, 112) 
order by CONVERT(char(6), AdmissionDate+v.number, 112), Location 

这是SQL Fiddle

- 另一个编辑

在审查另一个答案,并没有真正了解你的情况(需要一个期望输出),如果您想要的输出是在4月2日天为您的第一个记录,那么你只需要添加和v.number <> 0加入上面 - 很简单,只是不确定你在询问什么。这应该是最简单的解决方案:

select 
    CONVERT(char(6), AdmissionDate+v.number, 112) as CalendarMonth, 
    COUNT(*) Days, 
    Location 
from Visit t 
inner join master..spt_values v 
    on v.type='P' and v.number <= DATEDIFF(d, AdmissionDate, DischargeDate) and v.number <> 0 
group by Location, CONVERT(char(6), AdmissionDate+v.number, 112) 
order by CONVERT(char(6), AdmissionDate+v.number, 112), Location 

更多fiddle

希望这可以帮助一些。

祝你好运。

+0

请阅读问题。这只会给出按入场日期分组的总天数。他希望看到入学日期和出院日期之间每个月的天数 – cha

+0

请参阅编辑 - 这会比使用CTE更好地表现。祝你好运。 – sgeddes

+0

这两个解决方案(Cha和这个)都可以工作,但是这个解决方案的性能要好得多。这就是为什么我把这个帖子标记为公认的答案。感谢你们两位。 – Thracian

1

这样做(SQLFiddle):

with everyday (VisitNo, Location, dateOfStay) 
AS (
    SELECT VisitNo, Location, dateadd(dd, 1, AdmissionDate) 
    FROM VISIT 
    UNION ALL 
    SELECT e.VisitNo, e.Location, dateadd(dd, 1, e.dateOfStay) 
    FROM VISIT v INNER JOIN everyday e ON v.VisitNo = e.VisitNo and 
    e.dateofStay < v.DischargeDate 
) 
SELECT CONVERT(VARCHAR(7), dateofstay, 121), VisitNo, Location, count(*) 
FROM everyday 
GROUP BY CONVERT(VARCHAR(7), dateofstay, 121), VisitNo, Location 
ORDER BY 2,1 
OPTION (MAXRECURSION 500); 

如果你想按位置只,用这一个:

with everyday (VisitNo, Location, dateOfStay) 
AS (
    SELECT VisitNo, Location, dateadd(dd, 1, AdmissionDate) 
    FROM VISIT 
    UNION ALL 
    SELECT e.VisitNo, e.Location, dateadd(dd, 1, e.dateOfStay) 
    FROM VISIT v INNER JOIN everyday e ON v.VisitNo = e.VisitNo and 
    e.dateofStay < v.DischargeDate 
) 
SELECT CONVERT(VARCHAR(7), dateofstay, 121), Location, count(*) 
FROM everyday 
GROUP BY CONVERT(VARCHAR(7), dateofstay, 121), Location 
ORDER BY 2,1 
OPTION (MAXRECURSION 500);