CREATE OR REPLACE PROCEDURE generate_insert_as
AUTHID CURRENT_USER
AS
   dbsource       VARCHAR2 (30)      := 'SOURCE';
   dbtarget       VARCHAR2 (30)      := 'TARGET';
   liscolcommon   VARCHAR2 (4000);
   liscoltarget   VARCHAR2 (4000);
   liscolsource   VARCHAR2 (4000);
   where_ids      VARCHAR2 (4000);
   insertstmt     VARCHAR2 (4000);
   deletestmt     VARCHAR2 (4000);
   hasclient      BOOLEAN;
   -- CREATE OR REPLACE DIRECTORY dir_tmp AS '/tmp'
   -- grant execute on utl_file to target
   f              UTL_FILE.file_type;
BEGIN
   f := UTL_FILE.fopen ('DIR_TMP', '04_InsertMigr.sql', 'w');
   UTL_FILE.put_line (f, '-- Started ' || SYSDATE);

   -- for each table common in source and target
   FOR t IN (SELECT   object_name AS table_name
                 FROM all_objects
                WHERE owner = dbsource AND object_type = 'TABLE'
             -- AND object_name = 'AD_ATTACHMENTNOTE'
             INTERSECT
             SELECT   object_name
                 FROM all_objects
                WHERE owner = dbtarget AND object_type = 'TABLE'
             ORDER BY 1)
   LOOP
      liscolcommon := NULL;
      liscoltarget := NULL;
      liscolsource := NULL;
      where_ids := NULL;
      insertstmt := NULL;
      hasclient := FALSE;

      -- construct list of common columns
      FOR c IN (SELECT column_name
                  FROM all_tab_columns
                 WHERE owner = dbsource AND table_name = t.table_name
                INTERSECT
                SELECT column_name
                  FROM all_tab_columns
                 WHERE owner = dbtarget AND table_name = t.table_name)
      LOOP
         IF liscolcommon IS NULL
         THEN
            liscolcommon := c.column_name;
         ELSE
            liscolcommon := liscolcommon || ',' || CHR (10) || c.column_name;
         END IF;

         IF c.column_name LIKE '%\_ID' ESCAPE '\'
         THEN
            IF where_ids IS NULL
            THEN
               where_ids := c.column_name || '>=1000000';
            ELSE
               where_ids :=
                  where_ids || ' OR ' || CHR (10) || c.column_name
                  || '>=1000000';
            END IF;
         END IF;

         IF c.column_name = 'AD_CLIENT_ID'
         THEN
            hasclient := TRUE;
         END IF;
      END LOOP;

      -- construct list of columns only in target  (to review how to fill them)
      FOR c IN (SELECT column_name
                  FROM all_tab_columns
                 WHERE owner = dbtarget AND table_name = t.table_name
                MINUS
                SELECT column_name
                  FROM all_tab_columns
                 WHERE owner = dbsource AND table_name = t.table_name)
      LOOP
         IF liscoltarget IS NULL
         THEN
            liscoltarget := c.column_name;
         ELSE
            liscoltarget := liscoltarget || ', ' || c.column_name;
         END IF;
      END LOOP;

      -- construct list of columns only in source  (to review - data can be lost)
      FOR c IN (SELECT column_name
                  FROM all_tab_columns
                 WHERE owner = dbsource AND table_name = t.table_name
                MINUS
                SELECT column_name
                  FROM all_tab_columns
                 WHERE owner = dbtarget AND table_name = t.table_name)
      LOOP
         IF liscoltarget IS NULL
         THEN
            liscoltarget := c.column_name;
         ELSE
            liscoltarget := liscoltarget || ', ' || c.column_name;
         END IF;
      END LOOP;

      UTL_FILE.put_line (f, CHR (10) || '-- migrate table ' || t.table_name);

      IF liscoltarget IS NOT NULL
      THEN
         UTL_FILE.put_line (f, '-- columns in target: ' || liscoltarget);
      END IF;

      IF liscolsource IS NOT NULL
      THEN
         UTL_FILE.put_line (f, '-- columns in source: ' || liscolsource);
      END IF;

      deletestmt :=
            'DELETE FROM '
         || dbtarget
         || '.'
         || t.table_name
         || CASE
               WHEN where_ids IS NOT NULL
                  THEN CHR (10) || 'WHERE (' || where_ids || ')'
            END
         || ';'
         || CHR (10);
      UTL_FILE.put_line (f, deletestmt);
      insertstmt :=
            'INSERT INTO '
         || dbtarget
         || '.'
         || t.table_name
         || '('
         || liscolcommon
         || ')'
         || CHR (10)
         || 'SELECT '
         || liscolcommon
         || ' FROM '
         || dbsource
         || '.'
         || t.table_name
         || CASE
               WHEN where_ids IS NOT NULL AND hasclient
                  THEN    CHR (10)
                       || 'WHERE AD_CLIENT_ID<>11 AND ('
                       || where_ids
                       || ')'
               WHEN where_ids IS NOT NULL AND NOT hasclient
                  THEN CHR (10) || 'WHERE (' || where_ids || ')'
            END
         || ';';
      UTL_FILE.put_line (f, insertstmt);
   END LOOP;

   UTL_FILE.put_line (f, '-- End ' || SYSDATE);
   UTL_FILE.fclose (f);
END;
