Ric*_*lly 3 sql sql-server sql-server-2012
我有一个医疗报告项目,需要从诊断日期列表中计算"开始"日期.
患者第一次出现某种诊断,即发病日期为#1.在接下来的30天内,任何后续诊断日期都计入该发病次数的一部分,因此可以删除后续日期.
30天过后,下一个诊断日期计为起始#2.
等等..
示例输入
2015-09-10 (this is onset #1)
2015-09-19 (within 30 days from onset #1, so drop)
2015-09-29 (within 30 days from onset #1, so drop)
2015-10-17 (>= 30 days from onset #1, so this is onset #2)
2015-10-19 (within 30 days from onset #2, so drop)
2015-11-13 (within 30 days from onset #2, so drop)
2015-11-29 (>= 30 days from onset #2, so this is onset #3)
Run Code Online (Sandbox Code Playgroud)
示例输出
2015-09-10 (onset #1)
2015-10-17 (onset #2)
2015-11-29 (onset #3)
Run Code Online (Sandbox Code Playgroud)
这可以用光标完成,下面包含一个最小的例子.
我听说它说任何游标操作都可以表示为基于集合的操作.但我无法弄清楚如何以基于集合的方式处理这种特定算法,因为计算依赖于以前的算法.我看不出如何在一个基于集合的"通行证"中完成它.
可以吗?如果是这样,怎么样?
任何解决方案都应该在SQL Server 2012中运行.
DECLARE @dx_list TABLE(dx_dt date);
INSERT INTO @dx_list(dx_dt)
VALUES ('2015-09-10') --this is onset #1
, ('2015-09-19')
, ('2015-09-29')
, ('2015-10-17') --date is >= 30 days from last onset, so this is onset #2
, ('2015-10-19')
, ('2015-11-13')
, ('2015-11-29'); --date is >= 30 days from last onset, so this is onset #3
DECLARE @mycursor AS cursor;
SET @mycursor = CURSOR FOR
SELECT dx_dt
FROM @dx_list
ORDER BY dx_dt; --make sure dates are in order
DECLARE @possible_dt AS date;
DECLARE @onset_list TABLE(onset_dt date);
OPEN @mycursor;
FETCH NEXT FROM @mycursor INTO @possible_dt;
--First date is always an onset date
INSERT INTO @onset_list(onset_dt) VALUES (@possible_dt);
WHILE @@FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM @mycursor INTO @possible_dt;
--If this date is 30 days or more from last onset date, add it
IF @possible_dt >= DATEADD(dd, 30, (SELECT MAX(onset_dt) FROM @onset_list))
BEGIN
INSERT INTO @onset_list(onset_dt) VALUES (@possible_dt);
END
END
CLOSE @mycursor;
DEALLOCATE @mycursor;
--Show results
SELECT * FROM @onset_list;
Run Code Online (Sandbox Code Playgroud)
你可以使用递归CTE来做到这一点:
;WITH OnsetDates AS (
SELECT TOP 1 dx_dt
FROM dx_list
ORDER BY dx_dt
UNION ALL
SELECT dx_dt
FROM (
SELECT d1.dx_dt,
ROW_NUMBER() OVER (ORDER BY d1.dx_dt) AS rn
FROM dx_list AS d1
INNER JOIN OnsetDates AS d2 ON d1.dx_dt > d2.dx_dt
WHERE DATEDIFF(d, d2.dx_dt, d1.dx_dt) >= 30 ) AS t
WHERE t.rn = 1
)
SELECT *
FROM OnsetDates
Run Code Online (Sandbox Code Playgroud)
所谓固定件的CTE只是顶层的日期.该递归成员取出下一发病日期:这是第一次约会是过去30天+由递归CTE的前一个调用返回的日期.
请注意,为了获得第一个日期,我们必须使用ROW_NUMBER和子查询,因为TOP 1并且ORDER BY不允许在CTE的递归成员中.
| 归档时间: |
|
| 查看次数: |
321 次 |
| 最近记录: |