I am trying to build a script that takes the results from a table "ADMIN.ACCT_HRS" and creates INSERT INTO statements for each row, so that I could feasibly rebuild the table on another server via a DML statement. The search parameter for ACCT_HRS is the "WID", which I am pulling from the "ADMIN.INVENTORY" table using a user-inputted value, "pknum". This script is still in its infancy so I am only targeting one table; but eventually, I plan to adapt it to generate the INSERT INTO statements for six different tables with only one user-inputted value, all with constantly changing numbers of rows and columns. I could only figure out how to hardcode the column names that are being fetched (the following script works). I'm asking how to make this script dynamic for number of columns and column names.
**No, I cannot use external clients such as SQLcl **No, I cannot use a database link because the DML is being sent to a remote server that I have zero visibility on. **Yes, it has to be a PL/SQL that can be executed in Oracle to produce an output. **Yes, I realize there are easier ways and this is a pain in the @$$.
So far, my script looks like this:
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;
/
If that's so, then - in my opinion - you're choosing a wrong tool to do that. Oracle already has utility which is designed for such a purpose (moving data around), and it is called Data Pump. What does it do? It exports stuff here and imports it there. You will need DBA's assistance (unless you're the one) because you have to have access to Oracle directory.
On the other hand, there are still the original export and import utilities which work with .dmp file located on your own PC, i.e. you don't need Oracle directory.
Why is that approach better than yours? Because - as long as there's no problem in exporting simple datatypes (such as NUMBER or VARCHAR2) - there are other datatypes which aren't that simple to handle (DATE is the first one; not to mention BLOBs etc.).
Furthermore, export/import are fast; your row-by-row insert is slow (I wouldn't want to insert millions of rows that way).
Just as you said, it'll have to be dynamic. You'll probably have to query (in a loop)
user_tablesjoined touser_tab_columnsto get column names and their datatypes. Then compose statement you'llexecute immediate.It is kind of unclear what is desired result; you're printing result to the screen, which means that tool you use supports it (SQL*Plus, SQL Developer, TOAD and similar); then what? Copy/paste it elsewhere (into some file)? If so, why not spooling it?
I don't see any benefit in doing it your way and suggest you think it over and discard the idea altogether. Use export/import instead.
[EDIT] After reading your comment, it seems that you're using GUI tool for that purpose ("right click ... wizard ... copy/paste ...").
Furthermore, it seems that you didn't put any effort in reading documentation I posted. It exists for a reason. If you did that, you'd actually see that
expis a command line utility. It offers quite a few options you might want to use; one of them istablesparameter which lets you specify ALL tables you want to export. In a single command, without clicking, following the wizard, ....For example:
Now that you have .dmp file, you can import it into target schema using similar
impcommand.What's even better with that? You can put these commands into a batch file and schedule it (in MS Windows, it is Task Manager; on other operating systems, you'd use what they have for such a purpose) so that .dmp file either waits for you in the morning (ready to be imported) or - if possible - do it all for you (both export and import).
Someone said (I'm just repeating it): those who live by the GUI, die by the GUI. It helps, helps a lot - but only if you know how to properly use it.
Also, if the only tool you have is a hammer, every problem looks like a nail (but you wouldn't dig a hole using a hammer, would you?). That's why there are different tools for different problems.
Therefore, I still can't see why you think that export/import isn't the right choice for you, but OK - I won't try to stop you doing it your way. Good luck!