Last active
May 21, 2021 04:18
-
-
Save angoca/f41f8b7e71be8b701c3081bc06af2cab to your computer and use it in GitHub Desktop.
Generate Insert statement from Select
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--#SET TERMINATOR @ | |
--SET SERVEROUTPUT ON@ | |
/** | |
* Function that returns a string containing the insert statement with the | |
* values from the fields of a given row id. The case of the tableschame or of | |
* the tablename could be ignored if the name is stored in uppercase. | |
* This function does not generate the columns for the following datatypes: | |
* - XML | |
* - BLOB | |
* - BINARY | |
* - VARBINARY | |
* - BOOLEAN | |
* When a table only contains the previous values, then the statement cannot | |
* be generated. | |
* If you want to know how the function is working, you can activate the server | |
* output to see the partial queries: | |
* SET SERVEROUTPUT ON | |
* This function throws the following signals: | |
* - DBA01: When there is argument problem. | |
* - DBA02: If the tablel cannot be found. | |
* - DBA03: Table structure cannot be parsed. | |
* | |
* IN schemaname | |
* Schema of the table. If null, then current schema value will be used. | |
* IN tablename | |
* Name of the table. | |
* RETURNS A string with the Insert statement. | |
*/ | |
CREATE OR REPLACE FUNCTION generate_insert( | |
schemaname ANCHOR SYSCAT.TABLES.TABSCHEMA, | |
tablename ANCHOR SYSCAT.TABLES.TABNAME, | |
rownu INTEGER | |
) | |
RETURNS VARCHAR(32672) | |
BEGIN | |
DECLARE qty SMALLINT; | |
DECLARE stmt1 VARCHAR(32672); | |
DECLARE stmt2 VARCHAR(32672); | |
DECLARE INVALID_ARGUMENT CONDITION FOR SQLSTATE 'DBA01'; | |
DECLARE OBJECT_NOT_FOUND CONDITION FOR SQLSTATE 'DBA02'; | |
DECLARE cursor1 CURSOR FOR | |
WITH COLUMNS (SCHEMA, TABLE, COLUMN) AS ( | |
SELECT | |
TABSCHEMA, TABNAME, COLNAME | |
FROM SYSCAT.COLUMNS | |
WHERE TABSCHEMA = schemaname | |
AND TABNAME = tablename | |
AND TYPENAME NOT IN ('XML', 'BLOB', 'BINARY', 'VARBINARY' , 'BOOLEAN') | |
ORDER BY COLNO | |
) | |
SELECT | |
'SELECT ''INSERT INTO "' || SCHEMA || '"."' || TABLE | |
|| '" (' || LISTAGG('"' || COLUMN, '", ') || '") VALUES (''' | |
|| LISTAGG(' || CASE WHEN "' || COLUMN | |
|| '" IS NOT NULL THEN '''''''' || REPLACE("' || COLUMN | |
|| '", '''''''', '''''''''''') || '''''''' ELSE ''NULL'' END || ''', | |
', ''') || ')'' FROM "' || SCHEMA || '"."' || TABLE || '" WHERE RID() = ' | |
|| rownu | |
FROM COLUMNS | |
GROUP BY SCHEMA, TABLE | |
; | |
DECLARE cursor2 CURSOR | |
FOR dynsql; | |
DECLARE EXIT HANDLER FOR SQLSTATE '22004' | |
BEGIN | |
CALL DBMS_OUTPUT.PUT_LINE('Error during query'); | |
RESIGNAL SQLSTATE 'DBA03' | |
SET MESSAGE_TEXT = 'The table structure cannot be processed'; | |
END; | |
CALL DBMS_OUTPUT.PUT_LINE('Started'); | |
-- Validates the input parameters. | |
IF (tablename IS NULL OR tablename = '') THEN | |
SIGNAL INVALID_ARGUMENT | |
SET MESSAGE_TEXT = 'The tablename cannot be null or empty'; | |
END IF; | |
IF (rownu <= 0) THEN | |
SIGNAL INVALID_ARGUMENT | |
SET MESSAGE_TEXT = 'The rownumber cannot be zero or negative'; | |
END IF; | |
IF (schemaname = '') THEN | |
SIGNAL INVALID_ARGUMENT | |
SET MESSAGE_TEXT = 'The schemaname cannot be empty'; | |
END IF; | |
IF (schemaname IS NULL) THEN | |
SET schemaname = CURRENT SCHEMA; | |
END IF; | |
SET schemaname = TRIM(schemaname); | |
SET tablename = TRIM(tablename); | |
-- Checks if the table exists. | |
SET qty = ( | |
SELECT COUNT(1) | |
FROM SYSCAT.TABLES | |
WHERE TABSCHEMA = schemaname AND TABNAME = tablename); | |
IF (qty = 0) THEN | |
SET schemaname = UPPER(schemaname); | |
SET tablename = UPPER(tablename); | |
SET qty = ( | |
SELECT COUNT(1) | |
FROM SYSCAT.TABLES | |
WHERE TABSCHEMA = schemaname AND TABNAME = tablename); | |
IF (qty = 0) THEN | |
SIGNAL OBJECT_NOT_FOUND | |
SET MESSAGE_TEXT = 'The table object was not found.'; | |
ELSEIF (qty > 1) THEN | |
SIGNAL OBJECT_NOT_FOUND | |
SET MESSAGE_TEXT = 'Several objects has this name. SP error.'; | |
END IF; | |
ELSEIF (qty > 1) THEN | |
SIGNAL OBJECT_NOT_FOUND | |
SET MESSAGE_TEXT = 'Several objects has this name. SP error.'; | |
END IF; | |
-- Generates the Select to get the values from the table. | |
OPEN cursor1; | |
FETCH FROM cursor1 INTO stmt1; | |
CALL DBMS_OUTPUT.PUT_LINE(SUBSTR(stmt1, 1, 1000)); | |
CLOSE cursor1; | |
-- Generates the Insert statements with the field values. | |
PREPARE dynsql FROM stmt1; | |
OPEN cursor2; | |
FETCH FROM cursor2 INTO stmt2; | |
CALL DBMS_OUTPUT.PUT_LINE(SUBSTR(stmt2, 1, 1000)); | |
CLOSE cursor2; | |
CALL DBMS_OUTPUT.PUT_LINE('Finished'); | |
-- Result set with the insert values. | |
RETURN stmt2; | |
END | |
@ | |
-- Tests for signals. | |
-- Empty schema. ERROR raised. | |
VALUES SUBSTR(generate_insert('', 'EMPLOYEE', 1), 1, 100)@ | |
-- Table null. ERROR raised. | |
VALUES SUBSTR(generate_insert('DB2INST1', NULL, 1), 1, 100)@ | |
-- Table empty. ERROR raised. | |
VALUES SUBSTR(generate_insert('DB2INST1', '', 1), 1, 100)@ | |
-- Rowid -1. ERROR raised. | |
VALUES SUBSTR(generate_insert('DB2INST1', 'EMPLOYEE', -1), 1, 100)@ | |
-- Rowid 0. ERROR raised. | |
VALUES SUBSTR(generate_insert('DB2INST1', 'EMPLOYEE', 0), 1, 100)@ | |
-- Unexisting schema. ERROR raised. | |
VALUES SUBSTR(generate_insert('UNEXISTING', 'EMPLOYEE', 1), 1, 100)@ | |
-- Unexisting table. ERROR raised. | |
VALUES SUBSTR(generate_insert('DB2INST1', 'UNEXISTING', 1), 1, 100)@ | |
-- Creates tables for different kind of tests, and populates them. | |
CREATE TABLE TEST_ONE_TIME_COL (COL1 TIME)@ | |
INSERT INTO TEST_ONE_TIME_COL VALUES (CURRENT TIME)@ | |
CREATE TABLE TEST_ONE_DATE_COL (COL1 DATE)@ | |
INSERT INTO TEST_ONE_DATE_COL VALUES (CURRENT DATE)@ | |
CREATE TABLE TEST_ONE_TIMESTAMP_COL (COL1 TIMESTAMP)@ | |
INSERT INTO TEST_ONE_TIMESTAMP_COL VALUES (CURRENT TIMESTAMP)@ | |
CREATE TABLE TEST_ONE_CHAR_COL (COL1 CHAR(10))@ | |
INSERT INTO TEST_ONE_CHAR_COL VALUES ('CHAR')@ | |
CREATE TABLE TEST_ONE_VARCHAR_COL (COL1 VARCHAR(10))@ | |
INSERT INTO TEST_ONE_VARCHAR_COL VALUES ('CHAR')@ | |
CREATE TABLE TEST_ONE_CLOB_COL (COL1 CLOB)@ | |
INSERT INTO TEST_ONE_CLOB_COL VALUES ('CLOB')@ | |
CREATE TABLE TEST_ONE_GRAPHIC_COL (COL1 GRAPHIC(10))@ | |
INSERT INTO TEST_ONE_GRAPHIC_COL VALUES ('GRAPHIC')@ | |
CREATE TABLE TEST_ONE_VARGRAPHIC_COL (COL1 VARGRAPHIC(10))@ | |
INSERT INTO TEST_ONE_VARGRAPHIC_COL VALUES ('GRAPHIC')@ | |
CREATE TABLE TEST_ONE_DBCLOB_COL (COL1 DBCLOB)@ | |
INSERT INTO TEST_ONE_DBCLOB_COL VALUES ('DBCLOB')@ | |
CREATE TABLE TEST_ONE_SMALLINT_COL (COL1 SMALLINT)@ | |
INSERT INTO TEST_ONE_SMALLINT_COL VALUES (32767)@ | |
CREATE TABLE TEST_ONE_INT_COL (COL1 INTEGER)@ | |
INSERT INTO TEST_ONE_INT_COL VALUES (2147483647)@ | |
CREATE TABLE TEST_ONE_BIGINT_COL (COL1 BIGINT)@ | |
INSERT INTO TEST_ONE_BIGINT_COL VALUES (9223372036854775807)@ | |
CREATE TABLE TEST_ONE_DECIMAL_COL (COL1 DECIMAL(31,16))@ | |
INSERT INTO TEST_ONE_DECIMAL_COL VALUES (1234567890.0123456789)@ | |
CREATE TABLE TEST_ONE_DECFLOAT_COL (COL1 DECFLOAT)@ | |
INSERT INTO TEST_ONE_DECFLOAT_COL VALUES (-9.999999999999999e307)@ | |
INSERT INTO TEST_ONE_DECFLOAT_COL VALUES (1.000000000000000e-307)@ | |
INSERT INTO TEST_ONE_DECFLOAT_COL VALUES (NAN)@ | |
INSERT INTO TEST_ONE_DECFLOAT_COL VALUES (-SNAN)@ | |
INSERT INTO TEST_ONE_DECFLOAT_COL VALUES (INFINITY)@ | |
CREATE TABLE TEST_ONE_REAL_COL (COL1 REAL)@ | |
INSERT INTO TEST_ONE_REAL_COL VALUES (3.402E+38)@ | |
CREATE TABLE TEST_ONE_DOUBLE_COL (COL1 DOUBLE)@ | |
INSERT INTO TEST_ONE_DOUBLE_COL VALUES (1.79769E+308)@ | |
CREATE TABLE TEST_TWO_COLUMNS (COL1 INTEGER, COL2 CHAR(12))@ | |
INSERT INTO TEST_TWO_COLUMNS VALUES (1, 'A')@ | |
CREATE TABLE "TEST_Lower_Case" (COL1 INTEGER)@ | |
INSERT INTO "TEST_Lower_Case" VALUES (1)@ | |
CREATE TABLE TEST_LOWER_CASE ("ColLower" INTEGER)@ | |
INSERT INTO TEST_LOWER_CASE VALUES (1)@ | |
CREATE TABLE TEST_NULL (COL1 INTEGER)@ | |
INSERT INTO TEST_NULL VALUES (NULL)@ | |
CREATE TABLE TEST_SINGLE_QUOTE (COL1 VARCHAR(10))@ | |
INSERT INTO TEST_SINGLE_QUOTE VALUES ('O''connor')@ | |
CREATE TABLE TEST_DOUBLE_QUOTE (COL1 VARCHAR(10))@ | |
INSERT INTO TEST_DOUBLE_QUOTE VALUES ('"AngocA"')@ | |
CREATE TABLE TEST_DOUBLE_BYTE_CHAR (COL1 VARCHAR(20))@ | |
INSERT INTO TEST_DOUBLE_BYTE_CHAR VALUES (u&'Andr\00E9s')@ | |
CREATE TABLE TEST_MULTIPLE_ROWS (COL1 INTEGER, COL2 CHAR(10))@ | |
INSERT INTO TEST_MULTIPLE_ROWS VALUES | |
(1, 'A'), | |
(2, 'B'), | |
(3, 'C') | |
@ | |
-- Table with on time column. Null schema, then current schema. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_TIME_COL', 4), 1, 100)@ | |
-- Table with on date column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DATE_COL', 4), 1, 100)@ | |
-- Table with on timestamp column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_TIMESTAMP_COL', 4), 1, 100)@ | |
-- Table with on char column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_CHAR_COL', 4), 1, 100)@ | |
-- Table with on varchar column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_VARCHAR_COL', 4), 1, 100)@ | |
-- Table with on clob column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_CLOB_COL', 4), 1, 100)@ | |
-- Table with on graphic column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_GRAPHIC_COL', 4), 1, 100)@ | |
-- Table with on vargraphic column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_VARGRAPHIC_COL', 4), 1, 100)@ | |
-- Table with on dbclob column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DBCLOB_COL', 4), 1, 100)@ | |
-- Table with on smallint column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_SMALLINT_COL', 4), 1, 100)@ | |
-- Table with on int column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_INT_COL', 4), 1, 100)@ | |
-- Table with on bigint column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_BIGINT_COL', 4), 1, 100)@ | |
-- Table with on decimal column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DECIMAL_COL', 4), 1, 100)@ | |
-- Table with on decfloat column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DECFLOAT_COL', 4), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DECFLOAT_COL', 5), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DECFLOAT_COL', 6), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DECFLOAT_COL', 7), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DECFLOAT_COL', 8), 1, 100)@ | |
-- Table with on real column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_REAL_COL', 4), 1, 100)@ | |
-- Table with on double column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_DOUBLE_COL', 4), 1, 100)@ | |
-- Table with 2 columns. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_TWO_COLUMNS', 4), 1, 150)@ | |
-- Lower case tablename. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_Lower_Case', 4), 1, 100)@ | |
-- Lower case colname. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_LOWER_CASE', 4), 1, 100)@ | |
-- Null value. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_NULL', 4), 1, 100)@ | |
-- Single quote. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_SINGLE_QUOTE', 4), 1, 100)@ | |
-- Double quote. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_DOUBLE_QUOTE', 4), 1, 100)@ | |
-- Double byte characters. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_DOUBLE_BYTE_CHAR', 4), 1, 100)@ | |
-- Multiple rows. | |
SELECT SUBSTR(generate_insert(NULL, 'TEST_MULTIPLE_ROWS', RID()) || ';', 1, 99) | |
FROM TEST_MULTIPLE_ROWS@ | |
-- Name given in lowercase, converted to uppercase. | |
VALUES SUBSTR(generate_insert(NULL, 'test_one_int_col', 4), 1, 100)@ | |
-- Name given with extra spaces. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_INT_COL ', 4), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, ' TEST_ONE_INT_COL', 4), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, ' TEST_ONE_INT_COL ', 4), 1, 100)@ | |
-- Clean the database from test tables. | |
DROP TABLE TEST_MULTIPLE_ROWS@ | |
DROP TABLE TEST_DOUBLE_BYTE_CHAR@ | |
DROP TABLE TEST_DOUBLE_QUOTE@ | |
DROP TABLE TEST_SINGLE_QUOTE@ | |
DROP TABLE TEST_NULL@ | |
DROP TABLE TEST_LOWER_CASE@ | |
DROP TABLE "TEST_Lower_Case"@ | |
DROP TABLE TEST_TWO_COLUMNS@ | |
DROP TABLE TEST_ONE_DOUBLE_COL@ | |
DROP TABLE TEST_ONE_REAL_COL@ | |
DROP TABLE TEST_ONE_DECFLOAT_COL@ | |
DROP TABLE TEST_ONE_DECIMAL_COL@ | |
DROP TABLE TEST_ONE_BIGINT_COL@ | |
DROP TABLE TEST_ONE_INT_COL@ | |
DROP TABLE TEST_ONE_SMALLINT_COL@ | |
DROP TABLE TEST_ONE_DBCLOB_COL@ | |
DROP TABLE TEST_ONE_VARGRAPHIC_COL@ | |
DROP TABLE TEST_ONE_GRAPHIC_COL@ | |
DROP TABLE TEST_ONE_CLOB_COL@ | |
DROP TABLE TEST_ONE_VARCHAR_COL@ | |
DROP TABLE TEST_ONE_CHAR_COL@ | |
DROP TABLE TEST_ONE_TIMESTAMP_COL@ | |
DROP TABLE TEST_ONE_DATE_COL@ | |
DROP TABLE TEST_ONE_TIME_COL@ | |
--SET SERVEROUTPUT OFF@ | |
--========== | |
-- These are the cases for not supported data types. | |
-- XML could contain different characters that makes the query very complex. | |
-- BLOB has to be casted as | |
-- BINARY and VARBINARY are internal data types. | |
-- BOOLEAN is valid from 11.5. | |
CREATE TABLE TEST_ONE_XML_COL (COL1 XML)@ | |
INSERT INTO TEST_ONE_XML_COL VALUES ('<person/>')@ | |
INSERT INTO TEST_ONE_XML_COL VALUES ('<person><name>Andres</name></person>')@ | |
INSERT INTO TEST_ONE_XML_COL VALUES ('<person positition="dba"></person>')@ | |
CREATE TABLE TEST_ONE_BLOB_COL (COL1 BLOB)@ | |
INSERT INTO TEST_ONE_BLOB_COL VALUES (CAST('BLOB' AS BLOB))@ | |
CREATE TABLE TEST_ONE_BINARY_COL (COL1 BINARY)@ | |
INSERT INTO TEST_ONE_BINARY_COL VALUES ('BINARY')@ | |
CREATE TABLE TEST_ONE_VARBINARY_COL (COL1 VARBINARY)@ | |
INSERT INTO TEST_ONE_VARBINARY_COL VALUES ('VARBINARY')@ | |
CREATE TABLE TEST_ONE_BOOLEAN_COL (COL1 BOOLEAN)@ | |
INSERT INTO TEST_ONE_BOOLEAN_COL VALUES ('true')@ | |
-- Table with on xml column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_XML_COL', 4), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_XML_COL', 5), 1, 100)@ | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_XML_COL', 6), 1, 100)@ | |
-- Table with on blob column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_BLOB_COL', 4), 1, 100)@ | |
-- Table with on binary column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_BINARY_COL', 4), 1, 100)@ | |
-- Table with on varbinary column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_VARBINARY_COL', 4), 1, 100)@ | |
-- Only works with Db2 v11.5 or higher. | |
-- Table with on boolean column. | |
VALUES SUBSTR(generate_insert(NULL, 'TEST_ONE_BOOLEAN_COL', 4), 1, 100)@ | |
DROP TABLE TEST_ONE_XML_COL@ | |
DROP TABLE TEST_ONE_BLOB_COL@ | |
DROP TABLE TEST_ONE_BOOLEAN_COL@ | |
DROP TABLE TEST_ONE_VARBINARY_COL@ | |
DROP TABLE TEST_ONE_BINARY_COL@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment