可以提交应用于脚本中的每个INSERT INTO吗?

时间:2013-02-18 10:15:16

标签: oracle commit transaction-isolation

我刚刚从SQL Server迁移到ORACLE,我正在编写一个脚本(SQL Server样式)。 在SQL Server中,我们在脚本中应用一些逻辑后使用BEING TRAN - END TRAN。这可以在BEGIN-END块内完成。 在Oracle中,我发现这有点困难。经过大量谷歌搜索并在本网站上搜索后,我仍然不清楚如何满足这一要求。

当我运行脚本(粘贴在下面)时,它作为一个事务运行。一旦执行完整个脚本,DBMS_OUTPUT.Put_line也会显示。 有没有办法在每次提交后打印DBMS_OUTPUT.Put_line?

此外,如果有任何其他方法可以处理此脚本,我仍然愿意接受这些想法,以便每个子查询在脚本移动到下一个子查询之前提交...请告诉我。

这是我的剧本:

SET SERVEROUTPUT ON;
--spool Consolidated.log;
WHENEVER SQLERROR EXIT SQL.SQLCODE;
SET DEFINE OFF;

ALTER SESSION SET GLOBAL_NAMES=FALSE;

DECLARE
ExtractType         NUMBER(9);
RecordsExtracted    NUMBER(9);
CurStatus           NUMBER(9);
StartDate           date;
ErrorMessage        NVARCHAR2(1000);
LastExtrctTimestamp DATE;


BEGIN    
    -- AgreementTradeTypes
    StartDate := sysdate;
    ExtractType := 44;

    DELETE FROM AgreementTradeTypes;

    INSERT INTO AgreementTradeTypes (AgreementId,AgreementName,PrincipalId,Principal,CounterpartyId,Counterparty, TradeTypeId,TradeTypeName,BusinessLine,AdditionalCriteria)
    -- From CORE DB 
    SELECT  
            IATT.AgreementId, AG.AgreementName, IATT.PRINCIPALID, Principal.ENTITYNAME Principal, 
            IATT.COUNTERPARTYID, Cpty.ENTITYNAME Counterparty, 
            IATT.TradeTypeID, TT.TradeTypeName, BusLine.ENUMTEXT BusinessLine, IATT.ADDITIONALCRITERIA
    FROM    IncludedAgreementTradeTypes@RPTCORE IATT 
            INNER JOIN Entities@RPTCORE Principal ON IATT.PRINCIPALID = Principal.ENTITYID
            INNER JOIN Entities@RPTCORE Cpty ON IATT.CounterpartyId = Cpty.ENTITYID
            INNER JOIN EnumValues@RPTCORE BusLine ON IATT.BusinessLine = BusLine.ENUMVALUE AND BusLine.ENUMTYPE = 'BusinessLine'
            INNER JOIN Agreements@RPTCORE AG ON IATT.AGREEMENTID = AG.AgreementID
            INNER JOIN TradeTypes@RPTCORE TT ON IATT.TRADETYPEID = TT.TradeTypeID
    ORDER BY IATT.AgreementId;
    RecordsExtracted := SQL%RowCount;

    DBMS_OUTPUT.put_line('AgreementTradeTypes Records Extracted:' || RecordsExtracted);       

    -- On Success
    CurStatus := 2;
    ErrorMessage := 'AgreementTradeTypes Complete';

    INSERT INTO ExtractRecords(ExtractType, RecordsExtracted, Status, ExtractTimestamp, StartDate, EndDate, ErrorMessage)
    VALUES (ExtractType, RecordsExtracted, CurStatus, SysDate, StartDate, SysDate, ErrorMessage);

    INSERT INTO LoadRecords (LoadType,Status,LoadTimestamp,StartDate,EndDate) 
    VALUES (ExtractType, CurStatus, SysDate, StartDate, SysDate);

    COMMIT; /* Committing first Block */

    -- INTEREST PAYMENT PERIODS 
    StartDate := sysdate;
    ExtractType := 57;

    DELETE FROM InterestPaymentPeriods;

    INSERT INTO InterestPaymentPeriods (InterestPaymentPeriodId,AgreementId,AgreementName,CurrencyId,CurrencyName,InstrumentId,InstrumentName,PositionType,CollateralMarginType,PeriodStart,PeriodEnd,NextPeriodEnd,AccruedInterest,OpeningBalance,EndingBalance,MarketIndexId,MarketIndexName,Spread,DayCountConvention,CalculationType,ManagingLocation,BusinessLine)
    -- From CORE DB 
    SELECT
            IPP.INTERESTPAYMENTPERIODID, IPP.AGREEMENTID, AG.AGREEMENTNAME, IPP.CURRENCYID, CUR.CODE CurrencyName, IPP.INSTRUMENTID,
            Instruments.DESCRIPTION InstrumentName, PosType.ENUMTEXT PositionType, CollMargType.ENUMTEXT CollateralMarginType,
            IPP.PERIODSTART, IPP.PERIODEND, IPP.NEXTPERIODEND, IPP.ACCRUEDINTEREST, IPP.OPENINGBALANCE, IPP.ENDINGBALANCE,
            IPP.MARKETINDEXID, MI.MARKETINDEXNAME, IPP.SPREAD, DCC.ENUMTEXT DayCountConvention, CalcType.ENUMTEXT CalculationType,
            Cty.CITYNAME ManagingLocation, BusLine.ENUMTEXT BusinessLine
    FROM
            INTERESTPAYMENTPERIODS@RPTCORE IPP
            INNER JOIN Agreements@RPTCORE AG ON IPP.AGREEMENTID = AG.AGREEMENTID
            LEFT OUTER JOIN Currencies@RPTCORE CUR ON IPP.CURRENCYID = CUR.CURRENCYID
            LEFT OUTER JOIN Cities@RPTCORE Cty ON IPP.MANAGINGLOCATIONID = Cty.CITYID
            LEFT OUTER JOIN MarketIndexes@RPTCORE MI ON IPP.MARKETINDEXID = MI.MARKETINDEXID
            LEFT OUTER JOIN Instruments@RPTCORE ON IPP.INSTRUMENTID = Instruments.INSTRUMENTID
            LEFT OUTER JOIN EnumValues@RPTCORE PosType ON IPP.POSITIONTYPE = PosType.ENUMVALUE AND PosType.ENUMTYPE = 'PositionType'
            LEFT OUTER JOIN EnumValues@RPTCORE CollMargType ON IPP.COLLATERALMARGINTYPE = CollMargType.ENUMVALUE AND CollMargType.ENUMTYPE = 'CollateralMarginType'
            LEFT OUTER JOIN EnumValues@RPTCORE DCC ON MI.DAYCOUNTCONVENTION = DCC.ENUMVALUE AND DCC.ENUMTYPE = 'DayCountConvention'
            LEFT OUTER JOIN EnumValues@RPTCORE CalcType ON IPP.CALCULATIONTYPE = CalcType.ENUMVALUE AND CalcType.ENUMTYPE = 'CalculationType'
            LEFT OUTER JOIN EnumValues@RPTCORE BusLine ON IPP.BUSINESSLINE = BusLine.ENUMVALUE AND BusLine.ENUMTYPE = 'BusinessLine';
    RecordsExtracted := SQL%RowCount;       

    DBMS_OUTPUT.put_line('InterestPaymentPeriods Records Extracted:' || RecordsExtracted);

    -- On Success
    CurStatus := 2;
    ErrorMessage := 'Interest_Payment_Periods Complete';

    INSERT INTO ExtractRecords(ExtractType, RecordsExtracted, Status, ExtractTimestamp, StartDate, EndDate, ErrorMessage)
    VALUES (ExtractType, RecordsExtracted, CurStatus, SysDate, StartDate, SysDate, ErrorMessage);

    INSERT INTO LoadRecords (LoadType,Status,LoadTimestamp,StartDate,EndDate) 
    VALUES (ExtractType, CurStatus, SysDate, StartDate, SysDate);

    COMMIT; /* Committing Second Block */
END;

--spool off;
/

3 个答案:

答案 0 :(得分:5)

Oracle中的常规做法是仅在业务事务完成时提交,以便不对事务进行部分处理。这与其他系统不同,因为Oracle的多版本和锁定系统确保编写者不会阻止读者,读者也不会阻止编写者。

对于DBMS_Output问题,在块的执行过程中,您无法通过DBMS_Output从服务器获得响应。您可能希望使用Utl_File将数据写入服务器端文件。

其他想法:

  • 如果要删除每一行并且不需要对该表使用外键,请考虑使用TRUNCATE而不是DELETE。 TRUNCATE有一个与之关联的隐式提交,因此在过程开始时应用所有截断。

  • 如果要加载批量数据,要使用索引进行维护,并且不需要允许多次同时插入表中,请考虑在插入上使用APPEND提示来调用直接路径插入。

  • 我猜测插入的ORDER BY是有原因的 - 通常在Oracle中,它将确保数据行物理地聚集在order-by列上,这导致通过这些列提高基于索引的访问的效率。使用直接路径插入将有助于保证物理行排序,但如果您不需要该集群,则删除ORDER BY

答案 1 :(得分:1)

数据将分两个阶段进行。 DECLARE / BEGIN / END表示匿名PL/SQL block的开头和结尾,而不是交易。如果你没有在块中提交(这将更正常;在块内部进行事务控制有点不寻常),那么在块完成之后,你的任何更改都不会被提交 - 你仍然可以滚动如果你愿意,可以回来。

您的DBMS_OUTPUT调用将消息放入缓冲区,客户端(例如SQL * Plus)检索并在块完成后显示。没有办法 - 你无法使用该机制获得'实时'更新。有一些替代方法,例如使用UTL_FILEsetting module information进行可以从另一个会话中查看的会话,但这可能对您正在做的事情有些过分。

如果您只想在每个部分后看到该消息,可以将其拆分为两个匿名块。其缺点可能是必须将变量声明两次,并且它们将超出块之间的范围 - 因此您在第一个块中设置的内容将不会在第二个块中显示。您可以通过SQL * Plus variable命令使用绑定变量来解决这个问题。

你似乎根本不需要在PL / SQL中这样做,至少在这个例子中,尽管你说你将在脚本中应用一些逻辑。如果情况并非如此,那么你可以使用简单的SQL语句,替换变量和提示来实现这一点,而根本不使用PL / SQL。除了行计数之外,这有点棘手,除非你对正常的set feedback on显示感到满意,比如'3行插入'。

答案 2 :(得分:0)

DBMS_OUTPUT的结果仅在完成PL / SQL块后显示。 DBMS_OUTPUT和COMMIT彼此无关。如果您可以将脚本拆分为多个块,则可以在下一个块开始之前提交并打印每个块的结果。

begin
   -- step 1
   insert 
   commit ...
   dbms_output ...
end;
/

begin
   -- step 2
   insert...
   commit ...
   dbms_output ...
end;
/