我正在尝试构建一个脚本,该脚本从表“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;
/
...这样我就可以通过 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 等);然后呢?将其复制/粘贴到其他地方(到某个文件中)?既然如此,为什么不把它绕起来呢?
我认为按照你的方式做这件事没有任何好处,建议你仔细考虑一下并完全放弃这个想法。请改用导出/导入。