ORACLE:从“SELECT *”结果构建“INSERT INTO”语句

问题描述 投票:0回答:1

我正在尝试构建一个脚本,该脚本从表“ADMIN.ACCT_HRS”中获取结果并为每一行创建 INSERT INTO 语句,以便我可以通过 DML 语句在另一台服务器上重建表。 ACCT_HRS 的搜索参数是“WID”,我使用用户输入的值“pknum”从“ADMIN.INVENTORY”表中提取该参数。这个脚本仍处于起步阶段,所以我只针对一张表;但最终,我计划对其进行调整,以便为六个不同的表生成 INSERT INTO 语句,其中只有一个用户输入的值,所有这些表的行数和列数都在不断变化。我只能弄清楚如何对正在获取的列名称进行硬编码(以下脚本有效)。我问如何使该脚本针对列数和列名称动态化。

**不,我无法使用 SQLcl 等外部客户端 **不,我无法使用数据库链接,因为 DML 正在发送到我的可见性为零的远程服务器。 **是的,它必须是可以在 Oracle 中执行以产生输出的 PL/SQL。 **是的,我意识到有更简单的方法,但这对@$$来说是一个痛苦。

到目前为止,我的脚本如下所示:

DECLARE
    v_pknum VARCHAR2(16);
    v_sqlOutput VARCHAR2(4000);
    v_col_val VARCHAR2(4000);

    -- Variables for ACCT_HRS columns
    v_wid ADMIN.ACCT_HRS.WID%TYPE;
    v_hours_type_cd ADMIN.ACCT_HRS.HOURS_TYPE_CD%TYPE;
    v_wrk_dt ADMIN.ACCT_HRS.WRK_DT%TYPE;
    v_tech_id ADMIN.ACCT_HRS.TECH_ID%TYPE;
    v_tech_type ADMIN.ACCT_HRS.TECH_TYPE%TYPE;
    v_tech_class ADMIN.ACCT_HRS.TECH_CLASS%TYPE;
    v_man_hrs ADMIN.ACCT_HRS.MAN_HRS%TYPE;
    v_job_order ADMIN.ACCT_HRS.JOB_ORDER%TYPE;
    v_create_dt ADMIN.ACCT_HRS.CREATE_DT%TYPE;
    v_euser_id ADMIN.ACCT_HRS.EUSER_ID%TYPE;
    v_man_hrs_seq_no ADMIN.ACCT_HRS.MAN_HRS_SEQ_NO%TYPE;

    -- Cursor to fetch data
    CURSOR c_ACCT_HRS IS SELECT * FROM ADMIN.ACCT_HRS WHERE WID IN (SELECT WID FROM ADMIN.INVENTORY WHERE pknum = v_pknum);

BEGIN
    -- Prompt for pknum value
    DBMS_OUTPUT.PUT_LINE('Enter pknum:');
    v_pknum := '&pknum';

    -- Open the cursor
    OPEN c_ACCT_HRS;

    -- Loop to fetch each row
    LOOP
        -- Fetch the next row from the cursor into variables
        FETCH c_ACCT_HRS INTO v_wid, v_hours_type_cd, v_wrk_dt,
                               v_tech_id, v_tech_type, v_tech_class,
                               v_man_hrs, v_job_order, v_create_dt,
                               v_euser_id, v_man_hrs_seq_no;

        -- Exit the loop if no more rows
        EXIT WHEN c_ACCT_HRS%NOTFOUND;

        -- Initialize the output statement for each iteration
        v_sqlOutput := 'INSERT INTO ACCT_HRS (WID, HOURS_TYPE_CD, WRK_DT, TECH_ID, TECH_TYPE, TECH_CLASS, MAN_HRS, JOB_ORDER, CREATE_DT, EUSER_ID, MAN_HRS_SEQ_NO) VALUES (';

        -- Handle NULL values and construct the corresponding part of the INSERT INTO statement
        v_col_val := '';

        IF v_wid IS NOT NULL THEN v_col_val := v_col_val || '''' || v_wid || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_hours_type_cd IS NOT NULL THEN v_col_val := v_col_val || '''' || v_hours_type_cd || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_wrk_dt IS NOT NULL THEN v_col_val := v_col_val || '''' || v_wrk_dt || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_tech_id IS NOT NULL THEN v_col_val := v_col_val || '''' || v_tech_id || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_tech_type IS NOT NULL THEN v_col_val := v_col_val || '''' || v_tech_type || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_tech_class IS NOT NULL THEN v_col_val := v_col_val || '''' || v_tech_class || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_man_hrs IS NOT NULL THEN v_col_val := v_col_val || '''' || v_man_hrs || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_job_order IS NOT NULL THEN v_col_val := v_col_val || '''' || v_job_order || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_create_dt IS NOT NULL THEN v_col_val := v_col_val || '''' || v_create_dt || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_euser_id IS NOT NULL THEN v_col_val := v_col_val || '''' || v_euser_id || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        IF v_man_hrs_seq_no IS NOT NULL THEN v_col_val := v_col_val || '''' || v_man_hrs_seq_no || ''', ';
        ELSE v_col_val := v_col_val || 'NULL, ';
        END IF;

        -- Trim the trailing comma and add to the INSERT INTO statement
        v_sqlOutput := v_sqlOutput || RTRIM(v_col_val, ', ') || ');';

        -- Print the INSERT INTO statement for each row
        DBMS_OUTPUT.PUT_LINE(v_sqlOutput);

    END LOOP;

    -- Close the cursor
    CLOSE c_ACCT_HRS;

END;
/
oracle stored-procedures plsql dml sql-fetch
1个回答
0
投票

...这样我就可以通过 DML 语句在另一台服务器上重建表

如果是这样,那么 - 在我看来 - 你选择了错误的工具来做到这一点。 Oracle 已经拥有专为此目的(移动数据)而设计的实用程序,它被称为数据泵。它有什么作用?它在here导出内容并在there导入内容。您将需要 DBA 的帮助(除非您就是这样),因为您必须有权访问 Oracle 目录。

另一方面,仍然有原始导出和导入实用程序可以使用位于您自己的PC上的.dmp文件,即您不需要Oracle目录。

为什么这种方法比你的更好?因为 - 只要导出简单数据类型(例如 NUMBER 或 VARCHAR2)没有问题 - 还有其他数据类型处理起来并不那么简单(DATE 是第一个;更不用说 BLOB 等)。

此外,导出/导入也;你的逐行插入是(我不想以这种方式插入数百万行)。


我问如何使该脚本对于列数和列名称而言是动态的。

正如你所说,它必须是动态的。您可能需要(在循环中)查询连接到

user_tables
user_tab_columns
来获取列名称及其数据类型。然后撰写声明,您将
execute immediate

有点不清楚想要的结果是什么;您将结果打印到屏幕上,这意味着您使用的工具支持它(SQL*Plus、SQL Developer、TOAD 等);然后呢?将其复制/粘贴到其他地方(到某个文件中)?既然如此,为什么不把它绕起来呢?


我认为按照你的方式做这件事没有任何好处,建议你仔细考虑一下并完全放弃这个想法。请改用导出/导入。

© www.soinside.com 2019 - 2024. All rights reserved.