This document summarizes advanced data manipulation language (DML) techniques in Oracle, including conditional inserts, multi-table inserts, upserts (update/inserts), and updating or deleting rows using joins.
2. Agenda What is Advanced DML? Conditional Inserts Multi-table Inserts Upserts (Update/Insert) Updating via Joins
3. What is Advanced DML? Non-standard ways to insert, update, delete Includes variations on existing statements along with new statements Reduces need for procedural code (i.e. PL/SQL) Especially pertinent to data-warehouse environments
4. Inserts New (since 9i) variations allow you to: Insert rows into one of several tables Insert rows into multiple tables Insert different flavors of the same row multiple times
5. Insert First Allows each row to be placed into one of several tables using conditional logic. Example: Insert into either current or history table depending on date INSERT FIRST WHEN cal_dt = trunc(sysdate) THEN INTO pos_sum_dly VALUES (fund_id, cal_dt, security_id, …) WHEN cal_dt < trunc(sysdate) THEN INTO pos_sum_dly_hist VALUES (fund_id, cal_dt, security_id, …) SELECT fund_id, cal_dt, asset_id security_id, … FROM cus_pos_extrnl Insert today’s data into pos_sum_dly Insert old data into pos_sum_dly_hist
6. Insert All Allows each row to be placed into 0, 1, …N tables using conditional logic. Example: Insert data into pos_sum_dly, along with optional warnings INSERT ALL WHEN mtrty_dt IS NULL THEN INTO di_exception_rpt VALUES ( 'INFO:INVALID RSM_MATURITY_DATE in CUSPOS' , …) WHEN 1 = 1 THEN INTO pos_sum_dly VALUES (fund_id, cal_dt, security_id, …) SELECT fund_id, cal_dt, asset_id security_id, … FROM cus_pos_extrnl Insert warning record if maturity date is NULL Always insert into pos_sum_dly
7. Insert All (cntd) Allows different flavors of each row to be inserted into the same table. Example: Add pricing data going out 7 days INSERT ALL INTO pricing_master VALUES (sec_id, src_cd, prc_typ_cd, crncy_cd, effect_dt, …) INTO pricing_master VALUES (sec_id, src_cd, prc_typ_cd, crncy_cd, effect_dt + 1, …) … INTO pricing_master VALUES (sec_id, src_cd, prc_typ_cd, crncy_cd, effect_dt + 6, …) SELECT sec_id, src_cd, prc_typ_cd, crncy_cd, effect_dt, … FROM pricing_extrnl
8. INSERT/UPDATE Pre-9i implementation of INSERT/UPDATE logic… BEGIN INSERT INTO table_x (a, b, c, …) VALUES (v_1, v_2, v_3, …); EXCEPTION WHEN DUP_VAL_ON_INDEX UPDATE table_x SET b = v_2, c = v_3 WHERE a = v_1; END;
9. INSERT/UPDATE (cntd) New (9i) SQL command : MERGE Allows you to both update and insert with a single statement If a row already exists, data is updated; otherwise, data is inserted Also includes the ability to do conditional DELETE’s
10. Merge Allows data to be either updated or inserted using a single SQL statement. Example: MERGE INTO pos_sum_dly trg USING (SELECT fund_id, cal_dt, asset_id security_id, … FROM cus_pos_extrnl) src ON (trg.fund_id = src.fund_id, trg.cal_dt = src.cal_dt, …) WHEN MATCHED THEN UPDATE SET trg.mtrty_dt = src.pos_mtrty_dt, … WHEN NOT MATCHED THEN INSERT VALUES (src.fund_id, src.cal_dt, src.security_id, …) Row exists - Update No row exists - Insert
11. Merge (cntd) Don’t need to specify both WHEN MATCHED and WHEN NOT MATCHED Example: Fill in values for denormalized column MERGE /*+ PARALLEL(trg, 8) */ INTO income_recv_asof trg USING (SELECT /*+ FULL(ira) PARALLEL(ira, 8) USE_NL_WITH_INDEX(iraf, income_recv_asof_fin_key) */ ira.ssb_fund, ira.period_indicator, ira.income_instance, ira.asof_date, iraf.fin_currency FROM income_recv_asof ira, income_recv_asof_fin iraf WHERE ira.ssb_fund = iraf.ssb_fund AND ira.period_indicator = iraf.period_indicator AND ira.income_instance = iraf.income_instance AND ira.asof_date = iraf.asof_date AND ira.income_currency <> iraf.fin_currency ) src ON (src.ssb_fund = trg.ssb_fund AND src.period_indicator = trg.period_indicator AND src.income_instance = trg.income_instance AND src.asof_date = trg.asof_date) WHEN MATCHED THEN UPDATE SET trg.income_currency = src.fin_currency; Same table being updated…
12. Updating Using Joins SQL Server lets you do the following: UPDATE Sales.SalesPerson SET SalesYTD = SalesYTD + SubTotal FROM Sales.SalesPerson AS sp JOIN Sales.SalesOrderHeader AS so ON sp.SalesPersonID = so.SalesPersonID AND so.OrderDate = (SELECT MAX(OrderDate) FROM Sales.SalesOrderHeader WHERE SalesPersonID = sp.SalesPersonID);
13. Updating Using Joins (cntd) Doesn’t work with Oracle unless you update through an inline view: UPDATE (SELECT hdr.fund_type, dhr.fund_type new_typ FROM fund_header hdr INNER JOIN dhr_t dhr ON dhr.ssb_fund = hdr.ssb_fund ) SET fund_type = new_typ;
14. Updating Using Joins (cntd) However, opposite statement doesn’t work: UPDATE (SELECT dhr.fund_type, hdr.fund_type new_typ FROM dhr_t dhr INNER JOIN fund_header hdr ON dhr.ssb_fund = hdr.ssb_fund AND hdr.eval_ind = '0' ) SET fund_type = new_typ; Error at line 1 ORA-01779: cannot modify a column which maps to a non key-preserved table
15. Deleting Using Joins Again, only through an inline view: DELETE (SELECT hdr.ssb_fund FROM fund_header hdr INNER JOIN dhr_t dhr ON dhr.ssb_fund = hdr.ssb_fund WHERE hdr.tot_mkt_value < 1 AND dhr.max_bal < 100 ); Does it matter which columns are selected?