我需要构建一个查询,该查询将汇总已输入的血液单位数,以便将其与已交叉匹配的血液单位进行比较。血液(一种宝贵的资源)是交叉匹配但不输注的浪费。
提供商应该在创建新的交叉匹配订单之前检查系统记录(Epic)。不这样做的提供者是“受到惩罚的”(提供者20)。对于那些不会输入他们交叉匹配的所有血液的提供者(提供者10),不会受到惩罚(似乎)。
交叉匹配订单:
|ENC_ID|PROV_ID|ORDER_ID|ORDER_TIME |UNITS|
| 1| 10| 100|26-JUL-12 13:00| 4|
| 1| 20| 231|26-JUL-12 15:00| 2|
输血订单:
|ENC_ID|PROV_ID|ORDER_ID|ORDER_TIME |UNITS|
| 1| 10| 500|26-JUL-12 13:05| 1|
| 1| 10| 501|26-JUL-12 13:25| 1|
| 1| 20| 501|26-JUL-12 15:00| 1|
| 1| 20| 501|26-JUL-12 15:21| 2|
规则:
transfusion.END_ID=cross-match.ENC_ID
)transfusion.ORDER_TIME >= cross-match.ORDER_TIME
期望的结果:
|ENC_ID|PROV_ID|ORDER_ID|ORDER_TIME |CROSS-MATCHED|TRANSFUSED|
| 1| 10| 100|26-JUL-12 13:00| 4| 4|
| 1| 20| 231|26-JUL-12 15:00| 2| 1|
提供者10'在提供者20的输入中“记入”。
这种逻辑可以在不诉诸程序的情况下实施吗?
答案 0 :(得分:3)
您可以在单个SQL查询中执行此操作。这是一个例子(在11gR2上测试,应该在10g上工作):
SETUP:
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