3

这是我正在处理的内容:我得到了一个表(访问),其中包含示例数据的以下模式。

访问

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
.....................................................

要求是返回的数据集为如下结构。每个位置的总 LengthOfStay 按日历月 (YYYYMM)。

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

TotalLengthOfStayEachMonth 的计算有点棘手。从 AdmissionDate (admissionToDate) 算起的天数,而不是每月 30 天。例如, VISIT 表中的第一条记录有;

  • 201204入住2天
  • 2+30 = 201205 中的 32 天,依此类推...

提前感谢您的建议...仅供参考,我们有数百个地点、数千次访问和 5 年的数据。

4

2 回答 2

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 比 AdmissionDate 大 1 个月,则有些月份会丢失日期,并想出了这个——它使用了 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 小提琴

-- 另一个编辑

在查看另一个答案时,并没有真正了解您的情况(需要所需的输出),如果您的第一条记录所需的输出是 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

更多的小提琴

希望有些帮助。

祝你好运。

于 2013-01-21T05:16:37.283 回答
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);
于 2013-01-21T06:03:34.893 回答