0

我有以下问题,我有一个要使用 DBI CPAN 模块 Perl 执行的 SQL 文件我在这个网站上看到了两个解决方案来解决我的问题。

  1. 逐行读取 SQL 文件

  2. 一条指令读取 SQL 文件

那么,哪个更好,每种解决方案之间的真正区别是什么?

编辑

是为了图书馆。我需要检索输出返回码。

传递的文件类型可能如下:

    set serveroutput on;
    set pagesize 20000;
    spool "&1."
    DECLARE
        -- Récupération des arguments
        -- &2: FLX_REF, &3: SVR_ID, &4: ACQ_STT, &5: ACQ_LOG, &6: FLX_COD_DOC, &7: ACQ_NEL, &8: ACQ_TYP    
        VAR_FLX_REF VARCHAR2(100):=&2;
        VAR_SVR_ID NUMBER(10):=&3;
        VAR_ACQ_STT NUMBER(4):=&4;
        VAR_ACQ_LOG VARCHAR2(255):=&5;
        VAR_FLX_COD_DOC VARCHAR2(30):=&6;
        VAR_ACQ_NEL NUMBER(10):=&7;
        VAR_ACQ_TYP NUMBER:=&8;
    BEGIN
        INSERT INTO ACQUISITION_CFT 
            (ACQ_ID, FLX_REF, SVR_ID, ACQ_DATE, ACQ_STT, ACQ_LOG, FLX_COD_DOC, ACQ_NEL, ACQ_TYP) 
        VALUES 
            (TRACKING.SEQ_ACQUISITION_CFT.NEXTVAL, ''VAR_FLX_REF'', 
                ''VAR_SVR_ID'', sysdate, VAR_ACQ_STT, ''VAR_ACQ_LOG'',
                ''VAR_FLX_COD_DOC'', VAR_ACQ_NEL, VAR_ACQ_TYP);
    END;

    /
    exit;

我还有另一个问题要问,同样是 DBI Oracle 模块。我可以对 SQL 文件和控制文件使用相同的代码吗?

(SQL 控制文件示例)

    LOAD DATA
    APPEND INTO TABLE DOSSIER
    FIELDS TERMINATED BY ';'
    (
    DSR_IDT,
    DSR_CNL,
    DSR_PRQ,
    DSR_CEN,
    DSR_FEN,
    DSR_AN1,
    DSR_AN2,
    DSR_AN3,
    DSR_AN4,
    DSR_AN5,
    DSR_AN6,
    DSR_PI1,
    DSR_PI2,
    DSR_PI3,
    DSR_PI4,
    DSR_NP1,
    DSR_NP2,
    DSR_NP3,
    DSR_NP4,
    DSR_NFL,
    DSR_NPG,
    DSR_LTP,
    DSR_FLF,
    DSR_CLR,
    DSR_MIM,
    DSR_TIM,
    DSR_NDC,
    DSR_EMS NULLIF DSR_EMS=BLANKS "sysdate",
    JOB_IDT,
    DSR_STT,
    DSR_DAQ "CASE WHEN :DSR_DAQ IS NOT NULL THEN SYSDATE ELSE NULL END"

    )
4

3 回答 3

1

一次读取一行表格更复杂,但它可以使用更少的内存 - 只要您构建代码以利用每个项目的数据并且以后不需要全部。

通常您希望单独处理每个项目(例如,对数据进行处理),在这种情况下,您不妨使用逐行读取方法来定义您的循环。

默认情况下,我倾向于使用单指令方法,但是一旦我担心记录的数量(尤其是在长时间运行的批处理中),或者需要循环遍历数据作为第一个任务,那么我就会读取记录一个-一个。

于 2013-04-02T08:30:26.643 回答
1

实际上,您引用的两个答案提出了相同的解决方案,逐行阅读和执行(但第一个更清楚)。第二个问题有一个可选答案,其中文件包含一个语句

如果不逐行执行 SQL,则很难捕获任何错误。

于 2013-04-02T08:42:34.067 回答
1

“逐行”仅在每个 SQL 语句位于一行时才有意义。您可能的意思是逐个声明。

除此之外,这取决于您的 SQL 文件是什么样的以及您想要做什么。

您的 SQL 文件有多复杂? 它可以包含这样的东西吗?

select foo from table where column1 = 'bar;';   --Get foo; it will be used later.

按语句读取 SQL 文件语句的简单方法是用分号(或任何语句分隔符)分割。但是,如果您在其他地方可能有分号,例如注释或字符串,则此方法将失败。如果你用分号分割这条语句,你会尝试执行以下四个“命令”:

select foo from table where column1 = 'bar;
';
--Get foo; 
it will be used later.

显然,这些都不是有效的。正确处理这样的语句绝非易事。您必须完全解析 SQL 才能弄清楚语句是什么。不幸的是,没有现成的模块可以为您执行此操作(这SQL::Script是 SQL 文件处理模块的一个良好开端,但根据文档,此时它只是拆分为分号)。

如果您的 SQL 文件很简单,在语句或注释中不包含任何语句分隔符;或者如果它可以通过其他方式进行预测(例如每行有一个语句),那么很容易将文件拆分为语句并逐个执行它们。但是,如果您必须处理任意 SQL 语法,包括上述情况,这将是一项复杂的任务。

什么样的任务?

  • 您需要检索输出吗?
  • 检测任何单个语句中的错误是否重要,或者它只是一个可以运行而无需担心的批处理作业?

如果这是您可以运行并忘记的事情,您可以让 Perl 执行一个系统命令,告诉 Oracle 处理该文件。这将比自己处理所有语句更简单。但是,如果您需要在 Perl 中处理结果或处理错误,则必须逐个声明地自己处理。

更新:根据您的回复,您想编写一个可以处理任意 SQL 语句的库。在这种情况下,您肯定需要解析 SQL 并一次执行一条语句。这是可行的,但并不简单。块的可能性BEGIN...END意味着您必须能够正确处理语句中的分号。

SQL::Statement模块类可能会有所帮助。

于 2013-04-02T09:27:31.343 回答