• SQL Server与ORACLE数据库存储过程编写的几个不同之处


     一直在使用SQL Server数库的存储过程进行业务数据处理,现在ORACLE上进行存储过程应用,感觉没有MSSQL的方便灵活,总结了以下几点区别:

    1、入参数据类型不要书写长度。比如:userName VARCHAR2(100) 是不正确的。

    2、过程内变量声明必须在关键字IS/AS后,过程的开始BEGIN之间,且无需DECLARE关键字,变量名也无需@符号开头。而MSSQL是可以在过程体内任意位置通过Declare声明的。

    3、浮点类型的变量一定要声明成NUMBER类型,DECIMAL会有精度问题导致取值不是所期望的值。

    4、游标的使用如果是动态游标(并不是一开始就固定创建的,而是根据不同条件的生成的),必须先声明动态游标的类型和变量名。比如下例代码中的:

    TYPE ref_cur IS REF CURSOR;

    cur_stock REF_CUR; --库存处理游标

    5、SELECT语句对变量赋值语法:SELECT col1,col2 INTO var1,var2 FROM table1 WHERE ROWNUM=1,而MSSQL的语法是:SELECT @var1=col1,@var2=col2 FROM table1 WHERE id=1。

    6、如果上5中所说的变量赋值没有检索到记录还会触发 NO_DATA_FOUND THEN异常,可以用 EXCEPTION对异常进行捕获处理。而MSSQL没检索到数据变量会被赋值为NULL值。

    7、ORACLE的UPDATE语句内不能对变量进行更新操作,这一点真的是太不爽啦!!!。MSSQL是可以,例:DELCARE @NUM=0; UPDATE table1 SET @NUM=@NUM+1,col1=@NUM

    CREATE OR REPLACE PROCEDURE JUNAN.P_OPD_QUOTN_INS (
    --门诊医嘱签名过程 liuyc 20210902
    writeId IN INT, --待签名医嘱记录id
    operateId IN INT, --操作员id
    exprdate IN INT, --减少库存时批次:0不控制效期,1控制效期
    upstatus IN INT, --是否更新医嘱状态为已签名
    amount OUT NUMBER, --出库销售金额
    mess OUT VARCHAR2 --OK为执行成功
    )
    IS
    --本组变量保存医嘱信息
    ow_drugId VARCHAR2(30); --药品id
    ow_drugTypeId VARCHAR2(30); --药品类别id
    ow_unitName VARCHAR2(30); --药品单位名称
    ow_unitId NUMBER(12,0); --药品包装单位id
    ow_count NUMBER(12,4); --药品数量
    ow_baseCount NUMBER(12,4); --按基本单位算的药品数量
    ow_status VARCHAR2(4); --医嘱状态
    ow_patientId NUMBER(12,0); --患者id
    ow_deptId NUMBER(12,0); --药房id
    ow_hosId NUMBER(12,0); --医院id
    ow_relation NUMBER(12,6); --药品包装单位换算比
    --本组变量保存临时库存批次信息
    st_rowid ROWID; --库存批次表行系统rowid
    st_id INT; --库存游标保存变量 库存记录id
    st_unitId INT;  --库存包装单位id
    st_relation NUMBER(22,6);  --换算比
    st_count NUMBER(22,4);  --库存数量
    st_price NUMBER(22,6);  --药房包装单位的零售价格
    --其他变量
    per_quantity NUMBER(22,4) :=0;  --每次库存循环处理数量
    per_amount NUMBER(22,2) :=0; --每次库存循环处理金额
    total_quantity NUMBER(22,4) :=0;  --累计数量
    total_amount NUMBER(22,2) :=0; --累计金额
    operateName VARCHAR2(60); --操作员姓名
    TYPE ref_cur IS REF CURSOR;
    cur_stock REF_CUR; --库存处理游标
    BEGIN
    mess:='';
    --取得医嘱信息
      BEGIN
        SELECT DOCTOR_ORDER_ID,DRUG_COUNT,DRUG_COUNT_UNIT,DRUG_UNIT_ID,ORDER_STATUS_ID,PATIENT_ID,EXECUTIVE_SECTION_ID,HOSPITAL_ID
         INTO ow_drugId,ow_count,ow_unitName,ow_unitId,ow_status,ow_patientId,ow_deptId,ow_hosId
         FROM T_OPD_DOCTOR_ORDER_WRITE WHERE DOCTOR_ORDER_TYPE_ID='drug' AND id=writeId FOR UPDATE NOWAIT;
      EXCEPTION WHEN NO_DATA_FOUND THEN
        mess:='医嘱记录不存在!';
        RETURN;
      END;
      --只有医嘱状态0未签名、10审核驳回时可以做签名操作
      IF NVL(ow_status,'0') NOT IN ('0','10') THEN
        mess:=CONCAT('医嘱记录签名状态无效,值:',NVL(ow_status,''));
        RETURN;
      END IF;
    --取得门诊处方药品包装单位换算比,药品类别id
      BEGIN
        SELECT a.RELATION,b.DRUG_TYPE_ID INTO ow_relation,ow_drugTypeId from T_PHARMACY_DRUG_PACKAGE a
        INNER JOIN T_PHARMACY_DRUG b ON b.ID=A.DRUG_ID
        WHERE ROWNUM=1 and a.STATUS='1' and a.ID=ow_unitId;
      EXCEPTION WHEN NO_DATA_FOUND THEN
        mess:='查询药品包装单位换算比无数据!';
        RETURN;
      END;
      IF ow_relation IS NULL THEN
        mess:='药品包装单位换算比为null!';
        RETURN;
      END IF;
    --取操作员信息
      BEGIN
        SELECT name INTO operateName FROM T_SYS_OPERATOR WHERE id=operateId;
      EXCEPTION WHEN NO_DATA_FOUND THEN
        mess:='操作员记录不存在!';
        RETURN;
      END;
      IF NVL(ow_status,'')!=0 THEN
        mess:=CONCAT('医嘱记录签名状态无效,值:',NVL(ow_status,''));
        RETURN;
      END IF;
    --换算医嘱药品数量为基本单位数量
    ow_baseCount:=ROUND(ow_count*ow_relation,4);
    --打开动态游标,将临时库存中本药品有效批次库存的行id保存用于后续扣减处理
    open cur_stock FOR               
      SELECT ROWID FROM T_DRUGSTORE_DRUG_STOCK_TEMP T
      WHERE T.STATUS = '1' AND T.BATCH_INVALID = '1'
        AND (CASE WHEN exprdate=1 THEN T.EXPIRATION_DATE ELSE TO_DATE('9999-12-31','YYYY-MM-dd') END) >= trunc(sysdate)
        AND T.QUANTITY > 0 AND T.DEPT_ID=ow_deptId AND T.DRUG_ID =ow_drugId
      order by EXPIRATION_DATE;
    LOOP
    --遍历库存记录进行库存处理
      FETCH CUR_STOCK INTO st_rowid;
      exit when cur_stock%NOTFOUND;
      --取得当前id批次库存信息并锁定
      BEGIN
        SELECT ID,NEW_MAX_PACKAGE_UNIT_ID,RELATION,QUANTITY,DRUGSTORE_RETAIL_PRICE
          INTO st_id,st_unitId,st_relation,st_count,st_price FROM T_DRUGSTORE_DRUG_STOCK_TEMP WHERE QUANTITY > 0 AND ROWID=ST_ROWID
          FOR UPDATE;
      EXCEPTION WHEN NO_DATA_FOUND THEN
        CONTINUE;
      END;    
      --计算本批次扣减库存数量:批次库存小于等于待出库数量时取本批结余数,否则用待出库数
      PER_QUANTITY:=(CASE WHEN st_count<=ow_baseCount THEN st_count ELSE ow_baseCount END);
      --计算销售金额
      PER_AMOUNT:=ROUND(PER_QUANTITY/ST_RELATION*ST_PRICE,2);
      --更新本批次结存数量
      UPDATE T_DRUGSTORE_DRUG_STOCK_TEMP SET QUANTITY=QUANTITY-PER_QUANTITY,UPDATE_OPER=operateId,UPDATE_DATE=SYSDATE
        WHERE QUANTITY>=PER_QUANTITY AND ROWID=st_rowid;
      IF SQL%ROWCOUNT<1 THEN
        mess:='扣减临时库存更新了0行,库存数量有变化请重试!';
        RETURN;
      END IF;
      --写入药品划价记录
      INSERT INTO T_OPD_QUOTN (ID, HOSPITAL_ID, DEPT_ID, ORDER_WRITE_ID, STOCK_ID, DRUG_ID, UNIT_NAME, QUANTITY, PRICE, AMOUNT, RETURN_QUANTITY,
        CREATE_TIME,CREATE_OPER)
      VALUES (SEQ_OPD_QUOTN.NEXTVAL,OW_HOSID,OW_DEPTID,writeId,ST_ID,OW_DRUGID,OW_UNITNAME,
        ROUND(PER_QUANTITY/ow_relation,4),ROUND(PER_AMOUNT*ow_relation/PER_QUANTITY,4),PER_AMOUNT,0,SYSDATE,operateName);
      --更新累计出库数量和金额,待出库基本单位数量
      TOTAL_QUANTITY:=TOTAL_QUANTITY+PER_QUANTITY;
      TOTAL_AMOUNT:=TOTAL_AMOUNT+PER_AMOUNT;
      ow_baseCount:=ow_baseCount-PER_QUANTITY;
      IF ow_baseCount=0 THEN    
        EXIT; --库存数量足额扣减退出循环
      END IF;
    END LOOP;
    CLOSE CUR_STOCK;
    --循环结束判断待出库数量如果为非零,则说明不足出库
    IF ow_baseCount!=0 THEN    
      mess:=CONCAT('临时库存不足,待扣减基本单位数量:',TO_CHAR(ow_baseCount));
      RETURN;
    END IF;
    --库存扣减正常,更新门诊患者费用表金额信息,医嘱金额返回调用由代码修改
    UPDATE T_OPD_DOCTOR_COST SET TOTAL_SUM=TOTAL_AMOUNT,PRICE=ROUND(TOTAL_AMOUNT/ORDER_COUNT,4),UPDATE_OPER=operateId,UPDATE_DATE=SYSDATE 
      WHERE TOTAL_SUM!=TOTAL_AMOUNT AND HOSPITAL_ID=OW_HOSID AND ORDER_WRITE_ID=writeId;
    --更新医嘱药品费用金额
    UPDATE T_OPD_DOCTOR_ORDER_WRITE SET SUM_PRICE=TOTAL_AMOUNT,
      PRICE=(CASE WHEN DRUG_COUNT=0 THEN 0 ELSE ROUND(TOTAL_AMOUNT/DRUG_COUNT,4) END),
      ORDER_STATUS_ID=(CASE WHEN upstatus=1 THEN '1' ELSE ORDER_STATUS_ID END),UPDATE_DATE=SYSDATE
      WHERE id=writeId;
    amount:=TOTAL_AMOUNT;
    mess:='OK';
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        mess:='查询记录数据为空!';
      WHEN OTHERS THEN
        mess := SUBSTR(SQLERRM,1,2000);
    END P_OPD_QUOTN_INS;
    /
    凡哥,别他妈吹牛逼了
  • 相关阅读:
    [杂说]网络是基础生产工具
    这几天的工作
    [代码]大家来动动脑筋吧
    测试
    [基础] 如何使用extern和static限定符
    元宵节快乐
    复杂的“人"
    C# SMTP发邮件不支持465端口的解决方案,网易企业邮箱
    软件三层架构模型
    ASP.NET MVC 使用二级域名来注册Area区域
  • 原文地址:https://www.cnblogs.com/sdlz/p/15346796.html
Copyright © 2020-2023  润新知