首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 教學

Oracle 多表關聯數據匯總入庫:WITH 子查詢構建視圖再 INSERT 目標表完整實作

     編輯:Oracle 教學

Oracle 多表關聯數據匯總入庫:WITH 子查詢構建視圖再 INSERT 目標表完整實作

金融產品/資產管理系統常需從十餘張表關聯匯總計算每日收益、費用、管理費等指標,寫入彙總表供報表查詢。本文展示標準 WITH (CTE) → CREATE VIEW → INSERT SELECT 模式完整代碼結構。


業務場景

  • 核心表:GL_PRODUCTASSETS (產品-資產映射)、PRODUCT_INFO (產品主檔)、ASSETS_INFO (資產主檔)
  • 費率表:PRODUCT_COST_INFO (依產品/資產、費用類型存儲托管費/管理費/投顧費/浮動管理費等)
  • 浮動費用:PRODUCT_FMFEE (每日浮動管理費記錄)
  • 目標:計算每個產品/資產的**每日收益、累計收益、各類費用、淨收益**,寫入彙總表/視圖。

步驟 1:建立彙總視圖 (邏輯封裝、可複用)


CREATE OR REPLACE VIEW PARAMETER_VIEW AS
WITH
-- 1. 基礎關聯:產品-資產映射 + 主檔資訊
BASE AS (
  SELECT
    g.PBS_MAINPRO_NO AS PRODUCT_ID,
    p.PI_NO, p.PI_NAME, p.PI_START_DATE, p.PI_END_DATE,
    p.PI_CUSTOMER_YIELD/100 AS PROD_YIELD,
    a.AI_NO, a.CAS_ASSETS_NA, a.DONO,
    a.CAS_ISSUE_SUM, a.CAS_YIELD_RATE/100 AS ASSET_YIELD,
    a.CAS_VALUE_DATE, a.CAS_DUE_DATE,
    g.GL_STATE
  FROM GL_PRODUCTASSETS g
  LEFT JOIN PRODUCT_INFO p ON g.PBS_MAINPRO_NO = p.PI_NO
  LEFT JOIN ASSETS_INFO a ON g.CAS_ASSETS_NU = a.AI_NO
  WHERE g.GL_STATE = 1
),
-- 2. 浮動管理費彙總 (每產品累計)
FMFEE_SUM AS (
  SELECT PRODUCT_ID, SUM(FMFEE) AS FMFEE_TOTAL
  FROM PRODUCT_FMFEE
  GROUP BY PRODUCT_ID
),
-- 3. 當日浮動管理費
FMFEE_TODAY AS (
  SELECT PRODUCT_ID, SUM(FMFEE) AS FMFEE_DAILY
  FROM PRODUCT_FMFEE
  WHERE INPUT_DATE = TRUNC(SYSDATE)
  GROUP BY PRODUCT_ID
),
-- 4. 費率表拆解 (按費用類型、對象類型 PIVOT)
COST_RATES AS (
  SELECT
    FEEOBJECTNO,
    MAX(CASE WHEN FEEOBJECTTYPE='Product' AND FEETYPE='托管費' THEN FEERATIO/100 END) AS PROD_CUSTODY_RATE,
    MAX(CASE WHEN FEEOBJECTTYPE='Product' AND FEETYPE='管理費' THEN FEERATIO/100 END) AS PROD_MGMT_RATE,
    MAX(CASE WHEN FEEOBJECTTYPE='Product' AND FEETYPE='投顧費' THEN FEERATIO/100 END) AS PROD_ADV_RATE,
    MAX(CASE WHEN FEEOBJECTTYPE='Asset' AND FEETYPE='托管費' THEN FEERATIO/100 END) AS ASSET_CUSTODY_RATE,
    MAX(CASE WHEN FEEOBJECTTYPE='Asset' AND FEETYPE='管理費' THEN FEERATIO/100 END) AS ASSET_MGMT_RATE,
    MAX(CASE WHEN FEEOBJECTTYPE='Asset' AND FEETYPE='投顧費' THEN FEERATIO/100 END) AS ASSET_ADV_RATE,
    SUM(CASE WHEN FEEOBJECTTYPE='Product' AND FEETYPE NOT IN ('托管費','管理費','投顧費','浮動管理費') AND FEERATIO>1 THEN FEERATIO ELSE 0 END) AS PROD_OTHER_FEE_AMT,
    SUM(CASE WHEN FEEOBJECTTYPE='Product' AND FEETYPE NOT IN ('托管費','管理費','投顧費','浮動管理費') AND FEERATIO<1 THEN FEERATIO ELSE 0 END) AS PROD_OTHER_FEE_RATE
  FROM PRODUCT_COST_INFO
  GROUP BY FEEOBJECTNO
),
-- 5. 組裝完整計算基礎集
CALC_BASE AS (
  SELECT
    b.*,
    NVL(f1.FMFEE_TOTAL,0) AS FMFEE_TOTAL,
    NVL(f2.FMFEE_DAILY,0) AS FMFEE_DAILY,
    NVL(c.PROD_CUSTODY_RATE,0) AS PROD_CUSTODY_RATE,
    NVL(c.PROD_MGMT_RATE,0) AS PROD_MGMT_RATE,
    NVL(c.PROD_ADV_RATE,0) AS PROD_ADV_RATE,
    NVL(c.ASSET_CUSTODY_RATE,0) AS ASSET_CUSTODY_RATE,
    NVL(c.ASSET_MGMT_RATE,0) AS ASSET_MGMT_RATE,
    NVL(c.ASSET_ADV_RATE,0) AS ASSET_ADV_RATE,
    NVL(c.PROD_OTHER_FEE_AMT,0) AS PROD_OTHER_FEE_AMT,
    NVL(c.PROD_OTHER_FEE_RATE,0) AS PROD_OTHER_FEE_RATE,
    TRUNC(SYSDATE) AS CALC_DATE,
    FLOOR(TRUNC(SYSDATE) - TO_DATE(b.PI_START_DATE,'YYYY-MM-DD HH24:MI:SS')) AS PROD_ELAPSED_DAYS,
    FLOOR(TRUNC(SYSDATE) - TO_DATE(b.CAS_VALUE_DATE,'YYYY-MM-DD HH24:MI:SS')) AS ASSET_ELAPSED_DAYS
  FROM BASE b
  LEFT JOIN FMFEE_SUM f1 ON b.PRODUCT_ID = f1.PRODUCT_ID
  LEFT JOIN FMFEE_TODAY f2 ON b.PRODUCT_ID = f2.PRODUCT_ID
  LEFT JOIN COST_RATES c ON b.PI_NO = c.FEEOBJECTNO  -- 產品費率
  -- 資產費率需額外 JOIN ON b.AI_NO = c.FEEOBJECTNO (此處簡化)
)
-- 6. 最終指標計算
SELECT
  PRODUCT_ID, PI_NO, PI_NAME, PROD_YIELD, PI_START_DATE, PI_END_DATE,
  AI_NO, CAS_ASSETS_NA, DONO, CAS_ISSUE_SUM, ASSET_YIELD, CAS_VALUE_DATE, CAS_DUE_DATE,
  CALC_DATE,
  PROD_ELAPSED_DAYS, ASSET_ELAPSED_DAYS,
  -- 產品每日/累計收益
  PROD_YIELD * CAS_ISSUE_SUM / 365 AS PROD_DAILY_INCOME,
  PROD_YIELD * CAS_ISSUE_SUM / 365 * PROD_ELAPSED_DAYS AS PROD_TOTAL_INCOME,
  -- 產品各費用
  PROD_MGMT_RATE * CAS_ISSUE_SUM / 365 AS PROD_DAILY_MGMT_FEE,
  PROD_CUSTODY_RATE * CAS_ISSUE_SUM / 365 AS PROD_DAILY_CUSTODY_FEE,
  PROD_ADV_RATE * CAS_ISSUE_SUM / 365 AS PROD_DAILY_ADV_FEE,
  PROD_OTHER_FEE_AMT + PROD_OTHER_FEE_RATE * CAS_ISSUE_SUM / 365 AS PROD_DAILY_OTHER_FEE,
  -- 資產每日/累計收益
  ASSET_YIELD * CAS_ISSUE_SUM / 365 AS ASSET_DAILY_INCOME,
  ASSET_YIELD * CAS_ISSUE_SUM / 365 * ASSET_ELAPSED_DAYS AS ASSET_TOTAL_INCOME,
  -- 資產各費用
  ASSET_MGMT_RATE * CAS_ISSUE_SUM / 365 AS ASSET_DAILY_MGMT_FEE,
  ASSET_CUSTODY_RATE * CAS_ISSUE_SUM / 365 AS ASSET_DAILY_CUSTODY_FEE,
  ASSET_ADV_RATE * CAS_ISSUE_SUM / 365 AS ASSET_DAILY_ADV_FEE,
  -- 淨收益彙總
  (PROD_YIELD * CAS_ISSUE_SUM / 365
   - PROD_MGMT_RATE * CAS_ISSUE_SUM / 365
   - PROD_CUSTODY_RATE * CAS_ISSUE_SUM / 365
   - PROD_ADV_RATE * CAS_ISSUE_SUM / 365
   - (PROD_OTHER_FEE_AMT + PROD_OTHER_FEE_RATE * CAS_ISSUE_SUM / 365)
   + FMFEE_DAILY
   + ASSET_YIELD * CAS_ISSUE_SUM / 365
   - ASSET_MGMT_RATE * CAS_ISSUE_SUM / 365
   - ASSET_CUSTODY_RATE * CAS_ISSUE_SUM / 365
   - ASSET_ADV_RATE * CAS_ISSUE_SUM / 365
  ) AS NET_DAILY_INCOME
FROM CALC_BASE;

步驟 2:定時寫入彙總表 (ETL 排程)


-- 目標表結構對應視圖欄位
CREATE TABLE DAILY_PRODUCT_ASSET_SUMMARY (
  CALC_DATE DATE,
  PRODUCT_ID VARCHAR2(20),
  PI_NO VARCHAR2(20),
  PI_NAME VARCHAR2(100),
  PROD_DAILY_INCOME NUMBER(18,4),
  PROD_TOTAL_INCOME NUMBER(18,4),
  PROD_DAILY_MGMT_FEE NUMBER(18,4),
  PROD_DAILY_CUSTODY_FEE NUMBER(18,4),
  PROD_DAILY_ADV_FEE NUMBER(18,4),
  PROD_DAILY_OTHER_FEE NUMBER(18,4),
  ASSET_DAILY_INCOME NUMBER(18,4),
  ASSET_TOTAL_INCOME NUMBER(18,4),
  ASSET_DAILY_MGMT_FEE NUMBER(18,4),
  ASSET_DAILY_CUSTODY_FEE NUMBER(18,4),
  ASSET_DAILY_ADV_FEE NUMBER(18,4),
  NET_DAILY_INCOME NUMBER(18,4),
  -- 其他維度欄位...
  CONSTRAINT PK_DAILY_SUMMARY PRIMARY KEY (CALC_DATE, PRODUCT_ID)
);

-- 每日排程插入 (可用 DBMS_SCHEDULER 或作業系統排程)
INSERT INTO DAILY_PRODUCT_ASSET_SUMMARY (
  CALC_DATE, PRODUCT_ID, PI_NO, PI_NAME,
  PROD_DAILY_INCOME, PROD_TOTAL_INCOME,
  PROD_DAILY_MGMT_FEE, PROD_DAILY_CUSTODY_FEE, PROD_DAILY_ADV_FEE, PROD_DAILY_OTHER_FEE,
  ASSET_DAILY_INCOME, ASSET_TOTAL_INCOME,
  ASSET_DAILY_MGMT_FEE, ASSET_DAILY_CUSTODY_FEE, ASSET_DAILY_ADV_FEE,
  NET_DAILY_INCOME
)
SELECT
  CALC_DATE, PRODUCT_ID, PI_NO, PI_NAME,
  PROD_DAILY_INCOME, PROD_TOTAL_INCOME,
  PROD_DAILY_MGMT_FEE, PROD_DAILY_CUSTODY_FEE, PROD_DAILY_ADV_FEE, PROD_DAILY_OTHER_FEE,
  ASSET_DAILY_INCOME, ASSET_TOTAL_INCOME,
  ASSET_DAILY_MGMT_FEE, ASSET_DAILY_CUSTODY_FEE, ASSET_DAILY_ADV_FEE,
  NET_DAILY_INCOME
FROM PARAMETER_VIEW
WHERE CALC_DATE = TRUNC(SYSDATE);  -- 或指定業務日期

COMMIT;

關鍵設計模式總結

  1. WITH 子查詢 (CTE) 分層:基礎關聯 → 彙總中間表 → 費率 PIVOT → 組裝計算基礎 → 最終指標,邏輯清晰、易除錯、優化器易推導。
  2. 費率表 PIVOT 化:MAX(CASE...) 將垂直存儲的費率轉為橫向欄位,避免多次 JOIN 同一表,大幅提升效能。
  3. 視圖封裝邏輯:業務計算邏輯集中在視圖,ETL 僅負責 INSERT SELECT,修改邏輯只改視圖,不動表結構與排程代碼。
  4. 日期維度顯式化:CALC_DATE、ELAPSED_DAYS 明確記錄計算基準,支援歷史回補、跨日對賬。
  5. 主鍵設計:目標表主鍵 (CALC_DATE, PRODUCT_ID) 保冪等性,重跑不產生重複。

效能優化提示

  • 基礎表 (PRODUCT_INFO, ASSETS_INFO, PRODUCT_COST_INFO) 建立關聯欄位索引。
  • PRODUCT_FMFEE 建立 (PRODUCT_ID, INPUT_DATE) 複合索引支援當日/累計查詢。
  • 視圖若極複雜,考慮改為 物化視圖 (Materialized View) 定時刷新,查詢直接走預計算結果。
  • 大數據量分區表 (DAILY_PRODUCT_ASSET_SUMMARY 按 CALC_DATE Range 分區) 提升歷史資料管理與查詢效能。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved