oracle存儲過程 關於update的動態SQL-工作心得 oracle存儲過程 關於update的動態SQL-工作心得

oracle存儲過程 關於update的動態SQL-工作心得

本隨筆文章,由個人博客(鳥不拉屎)轉移至博客園
發佈時間: 2018 年 12 月 20 日
原地址:https://niaobulashi.com/archives/oracle-procedures-dynamicsql-update.html


花了我一下午時間,外加晚上加班
終於把存儲過程的主要功能給寫出來了!!!
emmmmm,做個筆記
後面有時間就細細分析下,先把代碼貼一下。

create or replace procedure P_SYNC_TA_PRODUCT_TEST(v_res           OUT NUMBER,
                                                       v_errorCode     OUT NVARCHAR2,
                                                       v_errorMsg      OUT NVARCHAR2,
                                                       d_dateStartDate IN NVARCHAR2,
                                                       d_dateEndDate   IN NVARCHAR2) IS
      --查詢是否存在已經同步的TA產品信息的個數
      v_count_updatePolling number(8) := 0;
      --收益率ID自動生成序列
      v_yieldRateId NVARCHAR2(36);
      --受益級別表的產品代碼
      v_productCode varchar2(36);
      --受益級別表的受益級別
      v_yieldLevelCode NVARCHAR2(10);
      --受益級別表的預期年化收益率
      v_yieldRate NVARCHAR2(20);
      v_yieldRateStr NVARCHAR2(20);
      --受益級別表的投資區間(開始)
      v_investmentIntervalS NVARCHAR2(20);
      v_investmentIntervalSStr NVARCHAR2(20);
      --受益級別表的投資區間(結束)
      v_investmentIntervalD NVARCHAR2(20);
      v_investmentIntervalDStr NVARCHAR2(20);
      --受益級別表的投資期限
      v_dueTime NVARCHAR2(20);
      --受益級別表的投資期限單位
      v_dueTimeUnit NVARCHAR2(2);
      --受益級別表的年化計算天數
      v_annualDays NVARCHAR2(5);
      --拼接的SQL語句
      v_confirmSql varchar2(600);
      v_confirmCommaSql varchar2(600);
      v_updateYieldRateSql varchar2(700);
      
      --用於判斷是否新增或更新
      /*v_total_pro number(8) := 0;
      --遊標tfundInfos的個數
      v_total number(8) := 0;
      --入池產品ID
      v_pollingProductId NVARCHAR2(36);
      --用於判斷產品表是否存在該產品
      v_count_pollingProduct number(8) := 0;
      --用於判斷是否存在已入池且當日改動的產品
      v_count_polling number(8) := 0;
      --用於判斷TA是否存在受益級別信息
      v_count_productRateYiled number(8) := 0;*/
    
      --1.定義遊標:查詢出產品名稱、成立日、預計到期日其中和TA不一致的產品信息
      CURSOR updateProductInfos IS
        select t.c_fundcode as fundCode, --產品代碼
               t.c_fundname as fundName, --產品名稱(TA)
               to_char(t.d_setupdate, 'yyyy-MM-dd') as setupDateStr, --成立日(TA)
               to_char(t.d_contractenddate, 'yyyy-MM-dd') as contractendDateStr --預計到期日期(TA)
          from tfundinfo@HSTA t
          inner join t_polling_product tpp
            on tpp.c_product_code = t.c_fundcode
            and tpp.delete_flag = '0'
         where 1 = 1
           and to_char(t.d_lastmodifydate, 'yyyy-MM-dd') >=
               to_char(to_date(d_dateStartDate, 'yyyy-MM-dd'), 'yyyy-MM-dd')
           and to_char(t.d_lastmodifydate, 'yyyy-MM-dd') <=
               to_char(to_date(d_dateEndDate, 'yyyy-MM-dd'), 'yyyy-MM-dd')
           and t.c_fundstatus <> '6'
           and (t.c_fundname <> tpp.c_product_name
           or to_char(t.d_setupdate, 'yyyy-MM-dd') <> to_char(tpp.c_found_date, 'yyyy-MM-dd')
           or to_char(t.d_contractenddate, 'yyyy-MM-dd') <> to_char(tpp.c_end_date, 'yyyy-MM-dd'));
           --排除已經結束的產品,0-募集期,1-正常,6-已結束
    
      --2.定義遊標:覈對受益級別數據後更新或新增家族信託產品受益級別
      CURSOR margeProductYieldRates IS
        select t.c_fundcode AS fundCode, --產品代碼
               tp.c_profitclass AS profitClass, --收益級別
               tp.f_profit*100 AS profit, --從TA獲取的收益率需要乘以100
               tp.f_amountmin AS amountMin, --投資下限(含)
               tp.f_amountmax AS amountMax, --投資上限(不含)
               tp.c_durationtime AS durationTime, --投資期限
               case tp.c_durationtimeunit
                 when '0' then 'Y'  --年
                 when '1' then 'M'  --月
                 when '2' then 'D'  --日
                 else ''
               end as durationTimeUnit, --期限單位
               case tp.c_bonusfrequency
                 when '0' then '04'
                 when '1' then '04'
                 when '2' then '04'
                 when '3' then '04'
                 when '4' then '04'
                 when '5' then '04' --特定週期
                 when '6' then '02' --到期一次性清算
                 when '7' then '03' --不定期
                 else ''
               end as bonusFrequencyType, --分配頻率類型
               case tp.c_bonusfrequency
                 when '2' then 'M' --每月
                 when '3' then 'Q' --每季度
                 when '4' then 'H' --每半年
                 when '5' then 'Y' --每年
                 else ''
               end as bonusFrequency, --分配頻率_特定
               tp.l_incomeyeardays as incomeYearDays, --年化天數
               NVL(to_char(t.d_setupdate, 'yyyy-MM-dd'),
                   to_char(sysdate, 'yyyy-MM-dd')) AS yieldStartDateStr --有效開始日期
          from tfundinfo@HSTA t
          inner join ttrustfundprofit@HSTA tp
            on tp.c_fundcode = t.c_fundcode
         where 1 = 1
           and to_char(t.d_lastmodifydate, 'yyyy-MM-dd') >=
               to_char(to_date(d_dateStartDate, 'yyyy-MM-dd'), 'yyyy-MM-dd')
           and to_char(t.d_lastmodifydate, 'yyyy-MM-dd') <=
               to_char(to_date(d_dateEndDate, 'yyyy-MM-dd'), 'yyyy-MM-dd')
           and t.c_fundstatus <> '6' and t.c_fundcode in ('CA0FX6','CA0FUC'); --排除已經結束的產品,0-募集期,1-正常,6-已結束
           
      
    begin
      --================================================================================
      -------------------------------【執行sql文】--------------------------------------
      --================================================================================
      --開啓日誌輸出緩衝
      DBMS_OUTPUT.ENABLE(buffer_size => null);
      DBMS_OUTPUT.put_line('----------------start------------------');
    
      
      --1.查詢是否存在已經同步的TA產品信息
      select count(*)
        into v_count_updatePolling
        from tfundinfo@HSTA t
        inner join t_polling_product tpp
          on tpp.c_product_code = t.c_fundcode
       where 1 = 1
         and to_char(t.d_lastmodifydate, 'yyyy-MM-dd') >=
             to_char(to_date(d_dateStartDate, 'yyyy-MM-dd'), 'yyyy-MM-dd')
         and to_char(t.d_lastmodifydate, 'yyyy-MM-dd') <=
             to_char(to_date(d_dateEndDate, 'yyyy-MM-dd'), 'yyyy-MM-dd')
         and t.c_fundstatus <> '6';     --排除已經結束的產品,0-募集期,1-正常,6-已結束
    
      --如果查詢到存在
      if v_count_updatePolling > 0 then
        
        --1.1 調用遊標:查詢出產品名稱、成立日、預計到期日其中和TA不一致的產品信息
        /*for updateProductInfo in updateProductInfos loop
          --非空判斷,如果查詢到的數據存在,表示,存在家族信託和TA不一致的產品信息,進行更新處理
          if updateProductInfo.Fundcode is not null then
            --查詢存在說明存在和TA不一致的產品基本信息,則更新和TA一致
            update t_polling_product t
               set t.c_product_name       = updateProductInfo.Fundname,
                   t.c_end_date           = to_date(updateProductInfo.Contractenddatestr, 'yyyy-MM-dd'),
                   t.update_time          = sysdate,
                   t.c_found_date         = to_date(updateProductInfo.Setupdatestr, 'yyyy-MM-dd')
             where t.c_product_code = updateProductInfo.Fundcode;
          end if;
        end loop;*/
        
        
        --1.2 調用遊標:覈對受益級別數據後更新或新增家族信託產品受益級別
        for margeProductYieldRate IN margeProductYieldRates loop
          if margeProductYieldRate.Fundcode is not null then
            /*
             * 1.2.1
             * 查詢TA中的受益級別,家族信託是否存在
             * 若存在,則表示家族和TA都存在該受益級別,進行覈對比較關鍵信息,發現不同則更新
             * 若不存在,表示家族這邊缺少TA的受益級別,需要從TA進行同步該受益級別
             */
            select tpy.c_product_code,
                   tpy.c_yield_level_code,
                   tpy.c_yield_rate,
                   tpy.c_investment_interval_s,
                   tpy.c_investment_interval_d,
                   tpy.c_due_time,
                   tpy.c_due_time_unit,
                   tpy.c_annual_days
              into v_productCode, --產品代碼
                   v_yieldLevelCode, --受益級別
                   v_yieldRate, --預期收益率
                   v_investmentIntervalS, --投資下限
                   v_investmentIntervalD, --投資上限
                   v_dueTime, --投資期限
                   v_dueTimeUnit, --投資期限單位
                   v_annualDays --年化天數
              from t_product_yield_rate tpy
             where tpy.c_yield_level_code = margeProductYieldRate.Profitclass
               and tpy.c_product_code = margeProductYieldRate.Fundcode
               and tpy.delete_flag = '0';
            
            --若存在,則表示家族和TA都存在該受益級別,進行覈對比較關鍵信息,發現不同則更新
            IF v_productCode is not null then
              /*
               * 將匹配的數據進行覈對,發現關鍵字段不匹配的進行更新
               * 對受益級別的關鍵字段進行一一對比
               * 對比不一樣的,進行拼接SQL
               */
              dbms_output.put_line('開始拼接SQL,產品代碼爲:' || margeProductYieldRate.Fundcode||','||'受益級別爲:'||margeProductYieldRate.Profitclass);
              
              --oracle  數據庫 字段值爲小於1的小數時,使用varchar2類型處理,會丟失小數點前面的0
              v_yieldRateStr := to_char(v_yieldRate, 'fm99999999990.00');
              v_investmentIntervalSStr := to_char(v_investmentIntervalS, 'fm99999999990.00');
              v_investmentIntervalDStr := to_char(v_investmentIntervalD, 'fm99999999990.00');
              
              dbms_output.put_line('1.收益率,family:' ||v_yieldRateStr||';'||'TA:'||to_char(margeProductYieldRate.Profit, 'fm99999999990.00'));
              -- 比較年化收益率
              if v_yieldRateStr is not null and margeProductYieldRate.Profit is not null then
                if v_yieldRateStr <> to_char(margeProductYieldRate.Profit, 'fm99999999990.00') then
                  v_confirmSql := v_confirmSql||'t.c_yield_rate='||to_char(margeProductYieldRate.Profit, 'fm99999999990.00')||',';
                end if;
              elsif v_yieldRateStr is null and to_char(margeProductYieldRate.Profit, 'fm99999999990.00') is not null then
                v_confirmSql := v_confirmSql||'t.c_yield_rate='||to_char(margeProductYieldRate.Profit, 'fm99999999990.00')||',';
              elsif v_yieldRateStr is not null and to_char(margeProductYieldRate.Profit, 'fm99999999990.00') is null then
                v_confirmSql := v_confirmSql||'t.c_yield_rate=null,';
              end if;
              --比較投資上限(含)
              dbms_output.put_line('2.投資上限,family:' || v_investmentIntervalSStr||';'||'TA:'||to_char(margeProductYieldRate.Amountmin, 'fm99999999990.00'));
              if v_investmentIntervalSStr is not null and to_char(margeProductYieldRate.Amountmin, 'fm99999999990.00') is not null then
                if v_investmentIntervalSStr <> to_char(margeProductYieldRate.Amountmin, 'fm99999999990.00') then
                  v_confirmSql := v_confirmSql||'t.c_investment_interval_s='||to_char(margeProductYieldRate.Amountmin, 'fm99999999990.00')||',';
                end if;
              elsif v_investmentIntervalSStr is null and to_char(margeProductYieldRate.Amountmin, 'fm99999999990.00') is not null then
                v_confirmSql := v_confirmSql||'t.c_investment_interval_s='||to_char(margeProductYieldRate.Amountmin, 'fm99999999990.00')||',';
              elsif v_investmentIntervalSStr is not null and to_char(margeProductYieldRate.Amountmin, 'fm99999999990.00') is null then
                v_confirmSql := v_confirmSql||'t.c_investment_interval_s=null,';
              end if;
              --比較投資下限(不含)          
              dbms_output.put_line('2.投資下限,family:' || v_investmentIntervalDStr||';'||'TA:'||to_char(margeProductYieldRate.Amountmax, 'fm99999999990.00'));
              if v_investmentIntervalDStr is not null and to_char(margeProductYieldRate.Amountmax, 'fm99999999990.00') is not null then
                if v_investmentIntervalDStr <> to_char(margeProductYieldRate.Amountmax, 'fm99999999990.00') then
                  v_confirmSql := v_confirmSql||'t.c_investment_interval_d='||to_char(margeProductYieldRate.Amountmax, 'fm99999999990.00')||',';
                end if;
              elsif v_investmentIntervalDStr is null and to_char(margeProductYieldRate.Amountmax, 'fm99999999990.00') is not null then
                v_confirmSql := v_confirmSql||'t.c_investment_interval_d='||to_char(margeProductYieldRate.Amountmax, 'fm99999999990.00')||',';
              elsif v_investmentIntervalDStr is not null and to_char(margeProductYieldRate.Amountmax, 'fm99999999990.00') is null then
                v_confirmSql := v_confirmSql||'t.c_investment_interval_d=null,';
              end if;
              --比較投資期限
              dbms_output.put_line('3.投資期限,family:' || v_dueTime||';'||'TA:'||margeProductYieldRate.Durationtime);
              if v_dueTime is not null and margeProductYieldRate.Durationtime is not null then
                if v_dueTime <> margeProductYieldRate.Durationtime then
                  v_confirmSql := v_confirmSql||'t.c_due_time='||margeProductYieldRate.Durationtime||',';
                end if;
              elsif v_dueTime is null and margeProductYieldRate.Durationtime is not null then
                v_confirmSql := v_confirmSql||'t.c_due_time='||margeProductYieldRate.Durationtime||',';
              elsif v_dueTime is not null and margeProductYieldRate.Durationtime is null then
                v_confirmSql := v_confirmSql||'t.c_due_time=null,';
              end if;
              --比較投資期限單位
              dbms_output.put_line('4.投資期限單位,family:' || v_dueTimeUnit||';'||'TA:'||margeProductYieldRate.Durationtimeunit);
              if v_dueTimeUnit is not null and margeProductYieldRate.Durationtimeunit is not null then
                if v_dueTimeUnit <> margeProductYieldRate.Durationtimeunit then
                  v_confirmSql := v_confirmSql||'t.c_due_time_unit='||''''||margeProductYieldRate.Durationtimeunit||''''||',';
                end if;
              elsif v_dueTimeUnit is null and margeProductYieldRate.Durationtimeunit is not null then
                v_confirmSql := v_confirmSql||'t.c_due_time_unit='||''''||margeProductYieldRate.Durationtimeunit||''''||',';
              elsif v_dueTimeUnit is not null and margeProductYieldRate.Durationtimeunit is null then
                v_confirmSql := v_confirmSql||'t.c_due_time_unit=null,';
              end if;
              --比較年化計算天數
              dbms_output.put_line('5.年化計算天數,family:' || v_annualDays||';'||'TA:'||margeProductYieldRate.Incomeyeardays);
              if v_annualDays is not null and margeProductYieldRate.Incomeyeardays is not null then
                if v_annualDays <> margeProductYieldRate.Incomeyeardays then
                  v_confirmSql := v_confirmSql||'t.c_annual_days'||''''||margeProductYieldRate.Incomeyeardays||''''||',';
                end if;
              elsif v_annualDays is null and margeProductYieldRate.Incomeyeardays is not null then
                v_confirmSql := v_confirmSql||'t.c_annual_days='||''''||margeProductYieldRate.Incomeyeardays||''''||',';
              elsif v_annualDays is not null and margeProductYieldRate.Incomeyeardays is null then
                v_confirmSql := v_confirmSql||'t.c_annual_days=null,';
              end if;
              
              --判斷存在不一致的受益級別字段
              if v_confirmSql is not null then
                --將得到的拼接字符串,去掉最後的一個句號','
                select substr(v_confirmSql,1,length(v_confirmSql)-1) into v_confirmCommaSql from dual;
                v_updateYieldRateSql := 'update t_product_yield_rate t set '||v_confirmCommaSql||' where t.c_product_code=:1 and t.c_yield_level_code=:2';
                dbms_output.put_line('拼接的SQL爲:' || v_updateYieldRateSql);
                
                --執行更新SQL
                execute immediate v_updateYieldRateSql USING margeProductYieldRate.Fundcode, margeProductYieldRate.Profitclass;
                
                --本條記錄處理完成,將v_confirmSql、v_confirmSqlCount清空準備下條處理
                v_confirmSql := '';
                v_confirmCommaSql := '';
                v_updateYieldRateSql := '';
              end if;
              
              --若不存在,表示家族這邊缺少TA的受益級別,需要從TA進行同步該受益級別
            else
              --生成收益率ID主鍵的序列號
              select concat(to_char(sysdate, 'yyyyMMddHHmmss'),
                            trunc(dbms_random.value(100000, 999999)))
                into v_yieldRateId
                from dual;
              dbms_output.put_line('存在新增的受益級別,產品代碼爲:'||margeProductYieldRate.Fundcode||',受益級別爲:'||margeProductYieldRate.Profitclass);
              --將該受益級別同步到家族信託中
              insert into T_PRODUCT_YIELD_RATE
              (T_PRODUCT_YIELD_RATE.C_YIELD_RATE_ID,
               T_PRODUCT_YIELD_RATE.C_PRODUCT_CODE,
               T_PRODUCT_YIELD_RATE.C_PRODUCT_MANAGER_CODE,
               T_PRODUCT_YIELD_RATE.C_INVESTMENT_INTERVAL_S,
               T_PRODUCT_YIELD_RATE.C_INVESTMENT_INTERVAL_D,
               T_PRODUCT_YIELD_RATE.C_YIELD_RATE,
               T_PRODUCT_YIELD_RATE.DELETE_FLAG,
               T_PRODUCT_YIELD_RATE.CREATE_USER_ID,
               T_PRODUCT_YIELD_RATE.CREATE_TIME,
               T_PRODUCT_YIELD_RATE.UPDATE_USER_ID,
               T_PRODUCT_YIELD_RATE.UPDATE_TIME,
               T_PRODUCT_YIELD_RATE.C_YIELD_START_DATE,
               T_PRODUCT_YIELD_RATE.C_YIELD_END_DATE,
               T_PRODUCT_YIELD_RATE.C_CHANGE_REASON,
               T_PRODUCT_YIELD_RATE.C_YIELD_LEVEL_CODE,
               T_PRODUCT_YIELD_RATE.C_ALLOCATION_TYPE,
               T_PRODUCT_YIELD_RATE.C_ALLOCATION_TYPE_SP,
               T_PRODUCT_YIELD_RATE.C_ALLOCATION_TYPE_MD,
               T_PRODUCT_YIELD_RATE.C_ANNUAL_DAYS,
               T_PRODUCT_YIELD_RATE.C_DUE_TIME,
               T_PRODUCT_YIELD_RATE.C_DUE_TIME_UNIT)
            values
              (v_yieldRateId,
               margeProductYieldRate.Fundcode,
               '0',
               margeProductYieldRate.Amountmin,
               margeProductYieldRate.Amountmax,
               margeProductYieldRate.Profit,
               '0',
               '00000000000000000000',
               sysdate,
               '00000000000000000000',
               sysdate,
               to_date(margeProductYieldRate.Yieldstartdatestr, 'yyyy-MM-dd'),
               to_date('9999-12-31', 'yyyy-MM-dd'),
               '',
               margeProductYieldRate.Profitclass,
               margeProductYieldRate.Bonusfrequencytype,
               margeProductYieldRate.Bonusfrequency,
               '',
               margeProductYieldRate.Incomeyeardays,
               margeProductYieldRate.Durationtime,
               margeProductYieldRate.Durationtimeunit);
            end if;
          end if;
        end loop;
      end if;
    
      
      --輸出放回狀態信息
      v_res       := 0;
      v_errorCode := SQLCODE;
      v_errorMsg  := 'P_SYNC_TA_PRODUCT_TEST' || ':' || TO_CHAR(SQLERRM);
      DBMS_OUTPUT.put_line('----------------end------------------');
      --提交
      COMMIT;
      --異常處理
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.put_line('----------------error------------------');
        --事務回滾
        ROLLBACK;
        v_res       := -1;
        v_errorCode := SQLCODE;
        v_errorMsg  := 'P_SYNC_TA_PRODUCT_TEST' || ':' || TO_CHAR(SQLERRM);
    end P_SYNC_TA_PRODUCT_TEST;
posted @ 2019-03-11 22:34 南嶼北島 閱讀( ...) 評論( ...) 編輯 收藏
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章