这是我正在处理的事情: 我给了一个表(访问),其中包含以下带有示例数据的模式。
访问
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的计算有点棘手。自AdmissionDate(admissionToDate)以来的日期计算,而不是每月30天。 例如,VISIT表中的第一条记录有;
提前感谢您的建议......仅供参考,我们有数百个地点,数千个视频和5年的数据。
答案 0 :(得分: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 Fiddle。
- 另一个编辑
在查看另一个答案时,并没有真正了解您的情况(需要所需的输出),如果您的第一个记录的所需输出是4月2天,那么您只需要添加和v.number&lt;&gt; 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。
希望其中一些有用。
祝你好运。答案 1 :(得分: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);