您可以在单个 SQL 查询中执行此操作。这是一个示例(在 11gR2 上测试,应该在 10g 上工作):
设置:
CREATE TABLE cross_match as (
SELECT 1 ENC_ID, 10 PROV_ID, 100 ORDER_ID,
to_date('2012-07-26 13', 'yyyy-mm-dd hh24') ORDER_TIME, 4 UNITS
FROM DUAL
UNION ALL SELECT 1, 20, 231, to_date('2012-07-26 15', 'yyyy-mm-dd hh24'), 2 FROM DUAL
);
CREATE TABLE transfusion as (
SELECT 1 ENC_ID, 10 PROV_ID, 500 ORDER_ID,
to_date('2012-07-26 13:05', 'yyyy-mm-dd hh24:mi') ORDER_TIME, 1 UNITS
FROM DUAL
UNION ALL SELECT 1, 10, 501, to_date('2012-07-26 13:25', 'yyyy-mm-dd hh24:mi'), 1 FROM DUAL
UNION ALL SELECT 1, 20, 501, to_date('2012-07-26 15:00', 'yyyy-mm-dd hh24:mi'), 1 FROM DUAL
UNION ALL SELECT 1, 20, 501, to_date('2012-07-26 15:21', 'yyyy-mm-dd hh24:mi'), 2 FROM DUAL
);
以下查询将以数字方式构建血液单位列表,并将表中的每个单位连接到cross_match
表中对应的单位(如果存在)transfusion
:
WITH cross_order as (
SELECT rownum rn FROM DUAL
CONNECT BY level <= (SELECT MAX(units) FROM cross_match)
),
transfusion_order as (
SELECT rownum rn FROM DUAL
CONNECT BY level <= (SELECT MAX(units) FROM transfusion)
)
SELECT c.enc_id, c.prov_id, c.order_id, c.order_time,
count(*) cross_matched,
count(t.enc_id) transfused
FROM (SELECT cm.*,
row_number() over (partition by cm.enc_id
order by cm.order_time) cross_no
FROM cross_match cm
JOIN cross_order co ON cm.units >= co.rn) c
LEFT JOIN (SELECT t.*,
row_number() over (partition by t.enc_id
order by t.order_time) trans_no
FROM transfusion t
JOIN transfusion_order tor ON t.units >= tor.rn) t
ON c.enc_id = t.enc_id
AND c.cross_no = t.trans_no
GROUP BY c.enc_id, c.prov_id, c.order_id, c.order_time;
ENC_ID PROV_ID ORDER_ID ORDER_TIME CROSS_MATCHED TRANSFUSED
-----------------------------------------------------------
1 20 231 07/26/2012 2 1
1 10 100 07/26/2012 4 4
如果最大单元数仍然很小,这可能是有效的,否则这种一对一的关系可能会变得很麻烦。
这可以通过使用两侧的总单位而不是基本的 1-1 来改善。连接条件就像开始单元和结束单元之间的间隔交集:
SELECT c.enc_id, c.prov_id, c.order_id, c.order_time,
sum(c.unit_end - nvl(c.unit_start,0))/count(*) cross_matched,
sum(least(c.unit_end, t.unit_end)
-greatest(nvl(c.unit_start, 0), nvl(t.unit_start, 0))) transfused
FROM (SELECT cm.*,
sum(cm.units) over (partition by cm.enc_id
order by cm.order_time
rows between unbounded preceding
and 1 preceding) unit_start,
sum(cm.units) over (partition by cm.enc_id
order by cm.order_time) unit_end
FROM cross_match cm) c
LEFT JOIN (SELECT t.*,
sum(t.units) over (partition by t.enc_id
order by t.order_time
rows between unbounded preceding
and 1 preceding) unit_start,
sum(t.units) over (partition by t.enc_id
order by t.order_time) unit_end
FROM transfusion t) t
ON c.enc_id = t.enc_id
AND c.unit_end > nvl(t.unit_start, 0)
AND t.unit_end > nvl(c.unit_start, 0)
GROUP BY c.enc_id, c.prov_id, c.order_id, c.order_time;
ENC_ID PROV_ID ORDER_ID ORDER_TIME CROSS_MATCHED TRANSFUSED
-----------------------------------------------------------
1 20 231 07/26/2012 2 1
1 10 100 07/26/2012 4 4