如何处理XMLTable中的插入序列?

时间:2016-01-18 12:46:01

标签: oracle plsql oracle11g

我已经编写了一个PL / SQL函数,它以XML格式输入 下表:

TABLE: TBL_MEDICAL_CENTER_BILLS

Name          Null     Type          
------------- -------- ------------- 
MED_RECORDNO  NOT NULL NUMBER       
MED_EMPID              NVARCHAR2(10) 
MED_BILL_HEAD          NVARCHAR2(20) 
MED_DATE               DATE          
MED_AMOUNT             FLOAT(126)   

这是功能代码:

FUNCTION save_medical_center_bills(medical_bill_data NVARCHAR2 ) RETURN clob IS ret clob;
   xmlData XMLType;

   v_code  NUMBER;
   v_errm  VARCHAR2(100);

   BEGIN 
   xmlData:=XMLType(medical_bill_data);
   INSERT INTO TBL_MEDICAL_CENTER_BILLS SELECT x.* FROM XMLTABLE('/medical_center_bill'
                                                PASSING xmlData

                                                COLUMNS  MED_RECORDNO NUMBER  PATH 'MED_RECORDNO' default null,
                                                         MED_EMPID    NVARCHAR2(11)     PATH   'employee_id',
                                                         MED_BILL_HEAD  NVARCHAR2(20)     PATH   'bill_head' ,
                                                         MED_DATE DATE  PATH  'effective_date',
                                                         MED_AMOUNT    FLOAT       PATH    'bill_amount'
                                                        ) x;


     ret:=to_char(sql%rowcount);
COMMIT;

RETURN '<result><status affectedRow='||ret||'>success</status></result>';
EXCEPTION
WHEN OTHERS THEN
v_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1, 100);
DBMS_OUTPUT.PUT_LINE (v_code || ' ' || v_errm);
-- '<result><status>Error</status> <error_message>'|| 'Error Code:' || v_code || ' ' || 'Error Message:' || v_errm ||'</error_message> </result>';
RETURN '<result><status>Error</status> <error_message>'|| 'Error Message:' || v_errm ||'</error_message> </result>';

END save_medical_center_bills;

但是,我希望将表的第一列MED_RECORDNO保持为递增序列(此时我保持为null,因为我不知道如何将序列放在XMLTable子句中)和其余的 输入[MED_EMPID,MED_BILL_HEAD,MED_DATE,MED_AMOUNT]将从传递给函数的XML中获取。

我创建了一个序列和一个触发器,以便为该表格列MED_RECORDNO增加此序列:

CREATE SEQUENCE MED_RECORDNO_SEQ;

create or replace TRIGGER MED_RECORDNO_TRIGGER 
BEFORE INSERT ON TBL_MEDICAL_CENTER_BILLS  FOR EACH ROW
WHEN (new.MED_RECORDNO is null)
DECLARE
  v_id TBL_MEDICAL_CENTER_BILLS.MED_RECORDNO%TYPE;
BEGIN
SELECT  MED_RECORDNO_seq.nextval INTO v_id FROM DUAL;
 :new.MED_RECORDNO  := v_id;

END;

如您所见,我的XMLTable在5列表中插入4个列值,因为列MED_RECORDNO将使用MED_RECORDNO_SEQ从序列TRIGGER MED_RECORDNO_TRIGGER获取其值。

我不知道这样做的任何事情。如果您曾经历过这样的事情,那么请分享您的想法。

1 个答案:

答案 0 :(得分:1)

我在之前的回答中暗示了这一点。您应该在要插入的表中指定列的名称;这是一个很好的做法,即使你正在填充所有这些,因为如果表结构发生变化(或环境不同),它将避免意外,并且更容易发现像列或值的顺序错误。

   INSERT INTO TBL_MEDICAL_CENTER_BILLS (MED_EMPID, MED_BILL_HEAD, MED_DATE, MED_AMOUNT)
   SELECT x.MED_EMPID, x.MED_BILL_HEAD, x.MED_DATE, x.MED_AMOUNT
   FROM XMLTABLE('/medical_center_bill'
      PASSING xmlData
      COLUMNS  MED_EMPID    NVARCHAR2(11)     PATH   'employee_id',
               MED_BILL_HEAD  NVARCHAR2(20)     PATH   'bill_head' ,
               MED_DATE DATE  PATH  'effective_date',
               MED_AMOUNT    FLOAT       PATH    'bill_amount'
              ) x;

您拥有的插入实际上应该有效(如果表中的列顺序匹配);触发器仍将使用序列值替换从XMLTable获取的null值。至少,直到你使MED_RECORDNO列不为空,并且你可能想要它是否是主键。

顺便提一下,如果您使用11g或更高级别,您的触发器可以将序列直接分配给新的伪记录:

create or replace TRIGGER MED_RECORDNO_TRIGGER 
BEFORE INSERT ON TBL_MEDICAL_CENTER_BILLS
FOR EACH ROW
BEGIN
   :new.MED_RECORDNO  := MED_RECORDNO_seq.nextval;
END;

when null检查意味着您有时希望允许指定值;这是一个坏主意,因为手动插入的值可能会与序列值发生冲突,无论是给出重复项还是唯一/主键异常。