1

我需要构建一个查询,该查询将汇总已输血的单位血液数量,以便可以将其与已交叉匹配的血液单位数量进行比较。交叉配血但不输血的血液(宝贵的资源)被浪费了。

供应商应该在创建新订单之前检查记录系统 (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
  • 提供者可以输血超过他们的交叉匹配订单,只要所有“有效”交叉匹配订单仍有可用单位(提供者 20 的第二个输血订单)

期望的结果:

|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 的输血。

这个逻辑可以在不诉诸程序的情况下实现吗?

4

1 回答 1

3

您可以在单个 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
于 2012-07-26T16:07:58.007 回答