-------------------------数据更新------------
--数据更新分为两种: 全量更新和增量更新。
--全量更新:删除整张表的数据,然后再把最新的全部数据插入到表中。
--适用范围:维度表(数据量少),数据量比较少的事实表或者宽表。
--增量更新:不删除或者删除部分表中数据,只把最新产生的数据插入到表中,历史数据不动。
--适用范围:数据量一定范围内增量比较大的表。一般是事实表或者宽表。


--------------------------------增量更新------------------------
--增量更新一共有4种方法。
---方法一:切片增量更新:按照时间将数据切成片,每次更新时只更新某一片或某几片数据。
----更新方法:先把目标时间范围内的数据删除(目标范围内存在数据就删除,不存在就不删),然后再把目标范围内的最新数据插入进去。

CREATE OR REPLACE PROCEDURE SP_DW_ROOM_DETAIL2(P_START_TIME VARCHAR2,P_END_TIME VARCHAR2) AS
V_START_TIME DATE := TO_DATE(P_START_TIME,'YYYY-MM-DD');
V_END_TIME DATE := TO_DATE(P_END_TIME,'YYYY-MM-DD');
BEGIN
  DELETE FROM DW_ROOM_DETAIL WHERE DATEKEY BETWEEN V_START_TIME AND V_END_TIME;
  INSERT INTO dw_room_detail
    (datekey, date_year, date_month, chainid, status_rmng, status_rm, amountrmng, roomamount, revenue)
  SELECT D.DATEKEY,
       D.YEARSS AS date_year,
       D.MONTHSS AS date_month,
       A.CHAINID,
       SUM(A.STATUSRMNG) AS status_rmng,
       SUM(A.STATUSRMNG+A.ROOMDAY+A.ROOMHALFDAY+A.ROOMHOURDAY) AS status_rm,
       SUM(NVL(B.AMOUNTRMNG,0)) AS AmountRmNg,
       SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)) AS RoomAmount,
       SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)+NVL(B.AMOUNTOTHER,0)) AS Revenue
FROM ODS.ODS_T_DATE D
  JOIN ODS.ODS_roomcount_detail A
    ON D.DATEKEY=TO_DATE(A.DATEKEY,'YYYYMMDD')
  JOIN ODS.ODS_ROOMAMOUNT_DETAIL B
    ON A.DATEKEY=B.DATEKEY
    AND A.CHAINID=B.CHAINID
    AND A.ROOMTYPEID=B.ROOMTYPEID
WHERE D.DATEKEY BETWEEN V_START_TIME AND V_END_TIME
GROUP BY D.DATEKEY,
       D.YEARSS,
       D.MONTHSS,
       A.CHAINID;
    COMMIT;
END;

-----------------------------

--方法二:使用merge..into..更新(只能在Oracle中使用)
--语法:

MERGE INTO 目标表 --目标表指的是要更新数据的表
USING (增量) --增量指的是SELECT查询语句  
ON (匹配字段)  --匹配字段指的是能匹配到一条数据的一个字段或者多个字段(一次只能匹配一条数据)
WHEN MATCHED THEN UPDATE SET --UPDATE 和 SET 之间不需要加表名,匹配字段不需要更新。
  WHEN NOT MATCHED THEN INSERT VALUES --INSERT 和 VALUES 之间不需要加 INTO 表名
    --注释:需要插入数据,说明匹配字段匹配不到,此时需要插入整条数据,一个字段都不能少。
CREATE OR REPLACE PROCEDURE SP_DW_ROOM_DETAIL3(P_START_TIME VARCHAR2,P_END_TIME VARCHAR2) AS
V_START_TIME DATE := TO_DATE(P_START_TIME,'YYYY-MM-DD');
V_END_TIME DATE := TO_DATE(P_END_TIME,'YYYY-MM-DD');
BEGIN
  MERGE INTO DW_ROOM_DETAIL M
  USING (SELECT D.DATEKEY,
                     D.YEARSS AS date_year,
                     D.MONTHSS AS date_month,
                     A.CHAINID,
                     SUM(A.STATUSRMNG) AS status_rmng,
                     SUM(A.STATUSRMNG+A.ROOMDAY+A.ROOMHALFDAY+A.ROOMHOURDAY) AS status_rm,
                     SUM(NVL(B.AMOUNTRMNG,0)) AS AmountRmNg,
                     SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)) AS RoomAmount,
                     SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)+NVL(B.AMOUNTOTHER,0)) AS Revenue
              FROM ODS.ODS_T_DATE D
                JOIN ODS.ODS_roomcount_detail A
                  ON D.DATEKEY=TO_DATE(A.DATEKEY,'YYYYMMDD')
                JOIN ODS.ODS_ROOMAMOUNT_DETAIL B
                  ON A.DATEKEY=B.DATEKEY
                  AND A.CHAINID=B.CHAINID
                  AND A.ROOMTYPEID=B.ROOMTYPEID
              WHERE D.DATEKEY BETWEEN V_START_TIME AND V_END_TIME
              GROUP BY D.DATEKEY,
                     D.YEARSS,
                     D.MONTHSS,
                     A.CHAINID) N
  ON (M.DATEKEY=N.DATEKEY AND M.CHAINID=N.CHAINID)
  WHEN MATCHED THEN UPDATE SET
       M.date_year =   N.date_year,
       M.date_month =  N.date_month,
       M.status_rmng = N.status_rmng,
       M.status_rm =   N.status_rm,
       M.amountrmng =  N.amountrmng,
       M.roomamount =  N.roomamount,
       M.revenue =     N.revenue
   WHEN NOT MATCHED THEN INSERT 
     (M.DATEKEY,
   M.DATE_YEAR,
   M.DATE_MONTH,
   M.CHAINID,
   M.STATUS_RMNG,
   M.STATUS_RM,
   M.AMOUNTRMNG,
   M.ROOMAMOUNT,
   M.REVENUE)
     VALUES 
       (N.DATEKEY,
   N.DATE_YEAR,
   N.DATE_MONTH,
   N.CHAINID,
   N.STATUS_RMNG,
   N.STATUS_RM,
   N.AMOUNTRMNG,
   N.ROOMAMOUNT,
   N.REVENUE);
   COMMIT;
   END;

-------------------------
--方法三:使用游标增量更新
--操作方法:先把增量放入游标中,然后在逻辑体中一条一条数据的去判断,如果能够匹配到这条数据,就更新为最新的数据,
--如果匹配不到,就把这条数据插入到目标表中。

CREATE OR REPLACE PROCEDURE SP_DW_ROOM_DETAIL4(P_START_TIME VARCHAR2,P_END_TIME VARCHAR2) AS
V_START_TIME DATE := TO_DATE(P_START_TIME,'YYYY-MM-DD');
V_END_TIME DATE := TO_DATE(P_END_TIME,'YYYY-MM-DD');
CURSOR C_DW_ROOM_DETAIL IS
SELECT D.DATEKEY,
                     D.YEARSS AS date_year,
                     D.MONTHSS AS date_month,
                     A.CHAINID,
                     SUM(A.STATUSRMNG) AS status_rmng,
                     SUM(A.STATUSRMNG+A.ROOMDAY+A.ROOMHALFDAY+A.ROOMHOURDAY) AS status_rm,
                     SUM(NVL(B.AMOUNTRMNG,0)) AS AmountRmNg,
                     SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)) AS RoomAmount,
                     SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)+NVL(B.AMOUNTOTHER,0)) AS Revenue
              FROM ODS.ODS_T_DATE D
                JOIN ODS.ODS_roomcount_detail A
                  ON D.DATEKEY=TO_DATE(A.DATEKEY,'YYYYMMDD')
                JOIN ODS.ODS_ROOMAMOUNT_DETAIL B
                  ON A.DATEKEY=B.DATEKEY
                  AND A.CHAINID=B.CHAINID
                  AND A.ROOMTYPEID=B.ROOMTYPEID
              WHERE D.DATEKEY BETWEEN V_START_TIME AND V_END_TIME
              GROUP BY D.DATEKEY,
                     D.YEARSS,
                     D.MONTHSS,
                     A.CHAINID;
V_CNT NUMBER;
BEGIN
  FOR X IN C_DW_ROOM_DETAIL LOOP
    SELECT COUNT(*) 
    INTO V_CNT
    FROM DW_ROOM_DETAIL B
    WHERE B.DATEKEY = X.DATEKEY
      AND B.CHAINID=X.CHAINID;
   IF V_CNT = 1 THEN 
     UPDATE DW_ROOM_DETAIL A SET
            A.date_year =   X.date_year,
       A.date_month =  X.date_month,
       A.status_rmng = X.status_rmng,
       A.status_rm =   X.status_rm,
       A.amountrmng =  X.amountrmng,
       A.roomamount =  X.roomamount,
       A.revenue =     X.revenue
     WHERE A.DATEKEY = X.DATEKEY
      AND A.CHAINID=X.CHAINID;
      ELSE INSERT INTO dw_room_detail
             (datekey, date_year, date_month, chainid, status_rmng, status_rm, amountrmng, roomamount, revenue)
           VALUES
            (X.DATEKEY,
   X.DATE_YEAR,
   X.DATE_MONTH,
   X.CHAINID,
   X.STATUS_RMNG,
   X.STATUS_RM,
   X.AMOUNTRMNG,
   X.ROOMAMOUNT,
   X.REVENUE);   
   END IF;
  END LOOP;
  COMMIT;
END;

-----------------------------
--方法四:利用异常处理的逻辑增量更新
--操作方法:先把增量数据放入游标中,在逻辑体中直接把增量数据一条一条的插入到目标表中,
---如果违反主键约束,则进入异常处理,改为更新这条数据。

CREATE OR REPLACE PROCEDURE SP_DW_ROOM_DETAIL5(P_START_TIME VARCHAR2,P_END_TIME VARCHAR2) AS
V_START_TIME DATE := TO_DATE(P_START_TIME,'YYYY-MM-DD');
V_END_TIME DATE := TO_DATE(P_END_TIME,'YYYY-MM-DD');
CURSOR C_DW_ROOM_DETAIL IS
SELECT D.DATEKEY,
                     D.YEARSS AS date_year,
                     D.MONTHSS AS date_month,
                     A.CHAINID,
                     SUM(A.STATUSRMNG) AS status_rmng,
                     SUM(A.STATUSRMNG+A.ROOMDAY+A.ROOMHALFDAY+A.ROOMHOURDAY) AS status_rm,
                     SUM(NVL(B.AMOUNTRMNG,0)) AS AmountRmNg,
                     SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)) AS RoomAmount,
                     SUM(NVL(B.AMOUNTRMNG,0)+NVL(B.AMOUNTRMALLDAY,0)+NVL(B.AMOUNTRMOTHER,0)+NVL(B.AMOUNTRMDISCOUNT,0)+NVL(B.AMOUNTOTHER,0)) AS Revenue
              FROM ODS.ODS_T_DATE D
                JOIN ODS.ODS_roomcount_detail A
                  ON D.DATEKEY=TO_DATE(A.DATEKEY,'YYYYMMDD')
                JOIN ODS.ODS_ROOMAMOUNT_DETAIL B
                  ON A.DATEKEY=B.DATEKEY
                  AND A.CHAINID=B.CHAINID
                  AND A.ROOMTYPEID=B.ROOMTYPEID
              WHERE D.DATEKEY BETWEEN V_START_TIME AND V_END_TIME
              GROUP BY D.DATEKEY,
                     D.YEARSS,
                     D.MONTHSS,
                     A.CHAINID;
BEGIN
  FOR X IN C_DW_ROOM_DETAIL LOOP
    BEGIN
    INSERT INTO dw_room_detail
      (datekey, date_year, date_month, chainid, status_rmng, status_rm, amountrmng, roomamount, revenue)
    VALUES
      (X.datekey, X.date_year, X.date_month, X.chainid, X.status_rmng, X.status_rm, X.amountrmng, X.roomamount, X.revenue);
EXCEPTION --一旦出现异常
   WHEN DUP_VAL_ON_INDEX THEN  
     UPDATE dw_room_detail A SET
      A.date_year =   X.date_year,
       A.date_month =  X.date_month,
       A.status_rmng = X.status_rmng,
       A.status_rm =   X.status_rm,
       A.amountrmng =  X.amountrmng,
       A.roomamount =  X.roomamount,
       A.revenue =     X.revenue
      WHERE A.DATEKEY=X.DATEKEY 
        AND A.CHAINID=X.CHAINID;  
      END;
  END LOOP;
  COMMIT;
END;