我正在重新发布这个问题,因为我还没有找到最佳解决方案。
我正在设计一张能够记录患者血液样本信息的表格。它有患者ID和收集日期 - 收集患者血液样本的日期。
该表还有三个附加列 - episode_number,episode_start_date和episode_end_date。一集不过是一个30天的时间窗口。 30天内收集的任何样本属于同一集。例如,患者于2013年1月1日提交了他的第一份血液样本,并于2013年1月19日提交了下一份血液样本。由于两个收集日期都在相同的“30天窗口”内,因此它们属于相同的episode_number(第1集)。这一集的开始日期将是第一个收集日期(2013年1月1日至2013年1月),结束日期将是开始日期+ 30天(2013年1月30日至1月30日)。在该日期范围内收集的任何数量的患者血液样本属于episode_number = 1。
假设同一名患者于2013年2月4日提交了另一份血液样本。由于该收集日期在episode_number = 1的30天窗口之外,因此它将属于新的episode_number(第2集)。本集的开始日期为2013年2月4日,结束日期为+ 30天,即2013年3月2日。
让我们说下面的示例表如下:
------------------------------------------------------------------------------------------
Patient ID | Collection_Date | Episode_Number |Episode_Start_Date | Episode_End_Date |
1 | 2013-01-01 | | | |
1 | 2013-01-01 | | | |
1 | 2013-01-05 | | | |
1 | 2013-02-04 | | | |
1 | 2013-02-06 | | | |
1 | 2013-05-01 | | | |
1 | 2013-08-01 | | | |
-------------------------------------------------------------------------------------------
我需要一个查询,根据我上面的文字中描述的逻辑填充episode_number,episode_start_Date和episode_end_date。查询结果应填充下面提到的表值:
----------------------------------------------------------------------------------------
Patient ID | Collection_Date |Episode_number |Episode_Start_Date| Episode_End_Date |
1 | 2013-01-01 |1 |2013-01-01 | 2013-01-30 |
1 | 2013-01-01 |1 |2013-01-01 | 2013-01-30 |
1 | 2013-01-05 |1 |2013-01-05 | 2013-01-30 |
1 | 2013-02-04 |2 |2013-02-04 | 2013-03-02 |
1 | 2013-02-06 |2 |2013-02-04 | 2013-02-04 |
1 | 2013-05-01 |3 |2013-05-01 | 2013-05-30 |
1 | 2013-08-01 |4 |2013-08-01 | 2013-08-30 |
----------------------------------------------------------------------------------------
要记住的事情:
我希望我的问题清楚明白。我的表有超过300万条记录,所以我不仅需要一个有效的解决方案,而且需要一个具有最佳性能的解决方案。任何帮助/建议将不胜感激。
提前致谢!
与Ashish
答案 0 :(得分:1)
(我暂时搁置一段时间,但这并没有实现collection_date必须在episode_start_date和episode_end_date之间的未表达的约束。)
让我们看一下这个表的一部分。
Patient ID | Collection_Date |Episode_number |Episode_Start_Date| Episode_End_Date |
1 | 2013-01-01 |1 |2013-01-01 | 2013-01-30 |
1 | 2013-01-01 |1 |2013-01-01 | 2013-01-30 |
重复行。这张桌子没有钥匙。
不同的东西这两个相同的行应该告诉我们什么?
这种表格呼唤真正的钥匙 - 而不仅仅是另一个身份证号码。
用于存储患者事件信息的表可能需要看起来像这样。
create table patient_episodes (
patient_id integer not null,
episode_number integer not null
check (episode_number > 0),
primary key (patient_id, episode_number),
foreign key (patient_id, episode_number)
references samples (patient_id, episode_number),
episode_start_date date not null,
episode_end_date date not null,
check (episode_end_date = episode_start_date + interval '30 days')
);
您需要最初从patient_episodes到样本声明外键引用,因为patient_episodes为空。我不清楚在两个表填充和稳定之后它是否应该保持这种状态。 (可能不是,但我不想猜。)
您的样品表仍然存在结构问题,因为它没有钥匙。如何解决该问题将对patient_episodes表的结构产生一些影响。
答案 1 :(得分:1)
如果您可以选择更改桌面设计,我建议Mike Sherill回答。
如果您没有该选项,则以下情况应该有效,但性能可能不佳:
with cte as
(select [Patient ID],
min(Collection_Date) Collection_Date,
1 Episode_Number,
min(Collection_Date) Episode_Start_Date,
Dateadd(d,29,min(Collection_Date)) Episode_End_Date
from sampleTable
group by [Patient ID]
union all
select s.[Patient ID],
s.Collection_Date Collection_Date,
c.Episode_Number+1 Episode_Number,
s.Collection_Date Episode_Start_Date,
Dateadd(d,29,s.Collection_Date) Episode_End_Date
from cte c
join sampleTable s
on c.[Patient ID] = s.[Patient ID] and
c.Episode_End_Date < s.Collection_Date and
not exists (select null
from sampleTable i
where c.[Patient ID] = i.[Patient ID] and
c.Episode_End_Date < i.Collection_Date and
i.Collection_Date < s.Collection_Date)
)
select cte.[Patient ID],
st.Collection_Date,
cte.Episode_Number,
cte.Episode_Start_Date,
cte.Episode_End_Date
from cte
join sampleTable st
on st.[Patient ID] = cte.[Patient ID] and
st.Collection_Date between cte.Episode_Start_Date and cte.Episode_End_Date
option (maxrecursion 0)
SQLFiddle here。