Reputation: 2276
The following function generates the SELECT to produce INSERT STATEMENT of the records of an Oracle table:
CREATE OR REPLACE FUNCTION GEN_INSERT_STATEMENT (IN_TABLE_NAME VARCHAR2)
RETURN CLOB
IS
LC$COLS_SELECT CLOB;
LC$COLS_VALUES CLOB;
LC$COLOUMN CLOB;
CURSOR LCUR$TAB_COLUMNS (IN_TABLE_NAME VARCHAR2)
IS
SELECT COLUMN_NAME, DATA_TYPE, COLUMN_ID
FROM USER_TAB_COLS
WHERE TABLE_NAME = IN_TABLE_NAME
ORDER BY COLUMN_ID;
BEGIN
FOR LREC$TAB_COLUMNS IN LCUR$TAB_COLUMNS (UPPER (IN_TABLE_NAME))
LOOP
LC$COLS_SELECT :=
LC$COLS_SELECT
|| CASE LREC$TAB_COLUMNS.COLUMN_ID WHEN 1 THEN '' ELSE ',' END
|| LREC$TAB_COLUMNS.COLUMN_NAME;
IF INSTR (LREC$TAB_COLUMNS.DATA_TYPE, 'CHAR') > 0
THEN
LC$COLOUMN :=
'''''''''||REPLACE('
|| LREC$TAB_COLUMNS.COLUMN_NAME
|| ','''''''','''''''''''')||''''''''';
ELSIF INSTR (LREC$TAB_COLUMNS.DATA_TYPE, 'DATE') > 0
THEN
LC$COLOUMN :=
'''TO_DATE(''''''||TO_CHAR(' || LREC$TAB_COLUMNS.COLUMN_NAME
|| ',''mm/dd/yyyy hh24:mi:ss'')||'''''',''''mm/dd/yyyy hh24:mi:ss'''')''';
ELSE
LC$COLOUMN := LREC$TAB_COLUMNS.COLUMN_NAME;
END IF;
LC$COLS_VALUES :=
LC$COLS_VALUES
|| CASE LREC$TAB_COLUMNS.COLUMN_ID WHEN 1 THEN '' ELSE ',' END
|| '''||DECODE('
|| LREC$TAB_COLUMNS.COLUMN_NAME
|| ',NULL,''NULL'','
|| LC$COLOUMN
|| ')||''';
END LOOP;
RETURN 'SELECT ''INSERT INTO '
|| IN_TABLE_NAME
|| ' ('
|| LC$COLS_SELECT
|| ') VALUES ('
|| LC$COLS_VALUES
|| ');'' FROM '
|| IN_TABLE_NAME
|| ';';
END;
/
The problem is that this function DOES NOT HANDLE the case in which are existing some VARCHAR2
fields with strings ending with: CHR(0)
Usage:
SELECT GEN_INSERT_STATEMENT ('MY_ORACLE_TABLE_NAME') FROM DUAL;
... generates a SELECT to produce the INSERT
statement.
If in a VARCHAR2
field the value ends with CHR(0)
, the INSERT
statement will be truncated exactly where is CHR(0)
located.
How can I fix this?
Upvotes: 1
Views: 3000
Reputation: 121
Use this:
Usage:
select fn_gen_inserts('select * from tablename', 'p_new_owner_name', 'p_new_table_name')
from dual;
where:
p_sql – dynamic query which will be used to export metadata rows
p_new_owner_name – owner name which will be used for generated INSERT
p_new_table_name – table name which will be used for generated INSERT
You can find original source code here:
Upvotes: 1
Reputation: 191235
If I understand what you're seeing, you need to either strip the null character from the value:
IF INSTR (LREC$TAB_COLUMNS.DATA_TYPE, 'CHAR') > 0
THEN
LC$COLOUMN :=
'''''''''||REPLACE(REPLACE('
|| LREC$TAB_COLUMNS.COLUMN_NAME
|| ',CHR(0),NULL),'''''''','''''''''''')||''''''''';
which gives your function the output:
SELECT 'INSERT INTO T42 (STR) VALUES ('||DECODE(STR,NULL,'NULL',''''||REPLACE(REPLACE(STR,CHR(0),NULL),'''','''''')||'''')||');' FROM T42;
and with a dummy table called t42
with a single column str
containing 'hello'
followed by a null character, the output is:
INSERT INTO T42 (STR) VALUES ('Hello');
Or preserve it during the insert:
LC$COLOUMN :=
'''''''''||REPLACE(REPLACE('
|| LREC$TAB_COLUMNS.COLUMN_NAME
|| ','''''''',''''''''''''),CHR(0),''''''||CHR(0)||'''''')||''''''''';
which gives:
SELECT 'INSERT INTO T42 (STR) VALUES ('||DECODE(STR,NULL,'NULL',''''||REPLACE(REPLACE(STR,'''',''''''),CHR(0),'''||CHR(0)||''')||'''')||');' FROM T42;
and finally:
INSERT INTO T42 (STR) VALUES ('Hello'||CHR(0)||'');
So in the second version the null character is removed from the fixed string (anywhere, not just at the end), and is put back as part of the insert statement.
This seems like a horrible approach though, when you could export the data, or let SQL Developer or some other IDE generate the insert statements for you. There maybe other data types and values that give you headaches, and which someone else has already worked hard to overcome. Unless you really need to be able to see the actual statements, using expdp
would be far simpler.
Upvotes: 2