Code.GeekInterview.com
  I am new, Sign me up!
 
Code Samples Oracle
 

Compare data in tables of the local Oracle schema


Code ResourceAuthor: Satheesh  

Difficulty Level:

Published: 5th Nov 2006   Read: 1777 times  

Filed in: Oracle
Add Comment


 


This script will compare the data in tables of the local Oracle schema to identically named tables in a remote Oracle schema and generate a  report of data discrepencies. For each table not containing identical rows in the two schemas, the report will include a SQL query you can run to display all of the differing data.

You can easily customize this script to only compare data in certain  tables, and also to exclude certain columns within each table from the  comparison.

This script will compare the data in tables of the local Oracle schema to identically named tables in a remote Oracle schema and generate a report of data discrepencies. For each table not containing identical rows in the two schemas, the report will include a SQL query you can run to display all of the differing data. You can easily customize this script to only compare data in certain tables, and also to exclude certain columns within each table from the comparison.

 


Sample Code
  1.  
  2. REM This script will compare the data IN tables OF the local Oracle SCHEMA
  3. REM TO identically named tables IN a remote Oracle SCHEMA AND generate a
  4. REM report OF data discrepencies. FOR each TABLE NOT containing identical
  5. REM ROWS IN the two schemas, the report will include a SQL query you can
  6. REM run TO display ALL OF the differing data.
  7. REM
  8. REM You can easily customize this script TO only compare data IN certain
  9. REM tables, AND also TO exclude certain columns within each TABLE FROM the
  10. REM comparison.
  11. REM
  12. REM Please note that the only way TO compare data IN tables IS TO read ALL
  13. REM OF the data FROM each TABLE. Although this script IS pretty efficient
  14. REM IN the way it does the comparison, comparing the contents OF large tables
  15. REM can be RESOURCE intensive AND can impact response TIME FOR other users.
  16. REM IF you will be USING this script TO compare large volumes OF data, please
  17. REM take this INTO consideration.
  18. REM
  19. REM Oracle 8 AND Oracle 8i DO NOT support fetching LOBs FROM remote tables,
  20. REM so data IN LOB columns are NOT compared BY this script. FOR similar
  21. REM reasons, LONGs AND LONG RAWs are NOT compared, either. Tables containing
  22. REM LOB OR LONG columns will be compared, but data IN the LOB AND LONG columns
  23. REM will be left OUT OF the comparison.
  24. REM
  25. REM Edit the following three DEFINE statements TO customize this script
  26. REM TO suit your needs.
  27. REM
  28.  
  29. REM Tables TO be compared:
  30.  
  31. DEFINE table_criteria = "table_name = table_name" -- all tables
  32. REM DEFINE table_criteria = "table_name != 'TEST'"
  33. REM DEFINE table_criteria = "table_name LIKE 'LOOKUP%' OR table_name LIKE 'C%'"
  34.  
  35. REM Columns TO be compared:
  36.  
  37. DEFINE column_criteria = "column_name = column_name" -- all columns
  38. REM DEFINE column_criteria = "column_name NOT IN ('CREATED', 'MODIFIED')"
  39. REM DEFINE column_criteria = "column_name NOT LIKE '%_ID'"
  40.  
  41. REM DATABASE LINK TO be used TO ACCESS the remote SCHEMA:
  42.  
  43. DEFINE dblink = "remote_db"
  44.  
  45. SET SERVEROUTPUT ON SIZE 1000000
  46. SET VERIFY OFF
  47.  
  48. DECLARE
  49.   CURSOR c_tables IS
  50.     SELECT   table_name
  51.     FROM     user_tables
  52.     WHERE    &table_criteria
  53.     ORDER BY table_name;
  54.   CURSOR c_columns (cp_table_name IN VARCHAR2) IS
  55.     SELECT   column_name, data_type
  56.     FROM     user_tab_columns
  57.     WHERE    table_name = cp_table_name
  58.     AND      &column_criteria
  59.     ORDER BY column_id;
  60.   TYPE t_char80array IS TABLE OF VARCHAR2(80) INDEX BY BINARY_INTEGER;
  61.   v_column_list     VARCHAR2(32767);
  62.   v_total_columns   INTEGER;
  63.   v_skipped_columns INTEGER;
  64.   v_count1          INTEGER;
  65.   v_count2          INTEGER;
  66.   v_rows_fetched    INTEGER;
  67.   v_column_pieces   t_char80array;
  68.   v_piece_count     INTEGER;
  69.   v_pos             INTEGER;
  70.   v_length          INTEGER;
  71.   v_next_break      INTEGER;
  72.   v_same_count      INTEGER := 0;
  73.   v_diff_count      INTEGER := 0;
  74.   v_error_count     INTEGER := 0;
  75.   v_warning_count   INTEGER := 0;
  76.   --
  77.   -- Use dbms_sql instead of native dynamic SQL so that Oracle 7 and Oracle 8
  78.   -- folks can use this script.
  79.   --
  80.   v_cursor          INTEGER := dbms_sql.open_cursor;
  81.   --
  82. BEGIN
  83.   --
  84.   -- Iterate through all tables in the local database that match the
  85.   -- specified table criteria.
  86.   --
  87.   FOR r1 IN c_tables LOOP
  88.     --
  89.     -- Build a list of columns that we will compare (those columns
  90.     -- that match the specified column criteria). We will skip columns
  91.     -- that are of a data type not supported (LOBs and LONGs).
  92.     --
  93.     v_column_list := NULL;
  94.     v_total_columns := 0;
  95.     v_skipped_columns := 0;
  96.     FOR r2 IN c_columns (r1.table_name) LOOP
  97.       v_total_columns := v_total_columns + 1;
  98.       IF r2.data_type IN ('BLOB', 'CLOB', 'NCLOB', 'LONG', 'LONG RAW') THEN
  99.         --
  100.         -- The column's data type is one not supported by this script (a LOB
  101.         -- or a LONG). We'll enclose the column name in comment delimiters in
  102.         -- the column list so that the column is not used in the query.
  103.         --
  104.         v_skipped_columns := v_skipped_columns + 1;
  105.         IF v_column_list LIKE '%,' THEN
  106.           v_column_list := RTRIM (v_column_list, ',') ||
  107.                            ' /*, "' || r2.column_name || '" */,';
  108.         ELSE
  109.           v_column_list := v_column_list || ' /* "' || r2.column_name ||'" */ ';
  110.         END IF;
  111.       ELSE
  112.         --
  113.         -- The column's data type is supported by this script. Add the column
  114.         -- name to the column list for use in the data comparison query.
  115.         --
  116.         v_column_list := v_column_list || '"' || r2.column_name || '",';
  117.       END IF;
  118.     END LOOP;
  119.     --
  120.     -- Compare the data in this table only if it contains at least one column
  121.     -- whose data type is supported by this script.
  122.     --
  123.     IF v_total_columns > v_skipped_columns THEN
  124.       --
  125.       -- Trim off the last comma from the column list.
  126.       --
  127.       v_column_list := RTRIM (v_column_list, ',');
  128.       BEGIN
  129.         --
  130.         -- Get a count of rows in the local table missing from the remote table.
  131.         --
  132.         dbms_sql.parse
  133.         (
  134.         v_cursor,
  135.         'SELECT COUNT(*) FROM (' ||
  136.         'SELECT ' || v_column_list || ' FROM "' || r1.table_name || '"' ||
  137.         ' MINUS ' ||
  138.         'SELECT ' || v_column_list || ' FROM "' || r1.table_name ||'"@&dblink)',
  139.         dbms_sql.native
  140.         );
  141.         dbms_sql.define_column (v_cursor, 1, v_count1);
  142.         v_rows_fetched := dbms_sql.execute_and_fetch (v_cursor);
  143.         IF v_rows_fetched = 0 THEN
  144.           RAISE NO_DATA_FOUND;
  145.         END IF;
  146.         dbms_sql.column_value (v_cursor, 1, v_count1);
  147.         --
  148.         -- Get a count of rows in the remote table missing from the local table.
  149.         --
  150.         dbms_sql.parse
  151.         (
  152.         v_cursor,
  153.         'SELECT COUNT(*) FROM (' ||
  154.         'SELECT ' || v_column_list || ' FROM "' || r1.table_name ||'"@&dblink'||
  155.         ' MINUS ' ||
  156.         'SELECT ' || v_column_list || ' FROM "' || r1.table_name || '")',
  157.         dbms_sql.native
  158.         );
  159.         dbms_sql.define_column (v_cursor, 1, v_count2);
  160.         v_rows_fetched := dbms_sql.execute_and_fetch (v_cursor);
  161.         IF v_rows_fetched = 0 THEN
  162.           RAISE NO_DATA_FOUND;
  163.         END IF;
  164.         dbms_sql.column_value (v_cursor, 1, v_count2);
  165.         --
  166.         -- Display our findings.
  167.         --
  168.         IF v_count1 = 0 AND v_count2 = 0 THEN
  169.           --
  170.           -- No data discrepencies were found. Report the good news.
  171.           --
  172.           dbms_output.put_line
  173.           (
  174.           r1.table_name || ' - Local and remote table contain the same data'
  175.           );
  176.           v_same_count := v_same_count + 1;
  177.           IF v_skipped_columns = 1 THEN
  178.             dbms_output.put_line
  179.             (
  180.             r1.table_name || ' - Warning: 1 LOB or LONG column was omitted ' ||
  181.             'from the comparison'
  182.             );
  183.             v_warning_count := v_warning_count + 1;
  184.           ELSIF v_skipped_columns > 1 THEN
  185.             dbms_output.put_line
  186.             (
  187.             r1.table_name || ' - Warning: ' || TO_CHAR (v_skipped_columns) ||
  188.             ' LOB or LONG columns were omitted from the comparison'
  189.             );
  190.             v_warning_count := v_warning_count + 1;
  191.           END IF;
  192.         ELSE
  193.           --
  194.           -- There is a discrepency between the data in the local table and
  195.           -- the remote table. First, give a count of rows missing from each.
  196.           --
  197.           IF v_count1 > 0 THEN
  198.             dbms_output.put_line
  199.             (
  200.             r1.table_name || ' - ' ||
  201.             LTRIM (TO_CHAR (v_count1, '999,999,990')) ||
  202.             ' rows on local database missing from remote'
  203.             );
  204.           END IF;
  205.           IF v_count2 > 0 THEN
  206.             dbms_output.put_line
  207.             (
  208.             r1.table_name || ' - ' ||
  209.             LTRIM (TO_CHAR (v_count2, '999,999,990')) ||
  210.             ' rows on remote database missing from local'
  211.             );
  212.           END IF;
  213.           IF v_skipped_columns = 1 THEN
  214.             dbms_output.put_line
  215.             (
  216.             r1.table_name || ' - Warning: 1 LOB or LONG column was omitted ' ||
  217.             'from the comparison'
  218.             );
  219.             v_warning_count := v_warning_count + 1;
  220.           ELSIF v_skipped_columns > 1 THEN
  221.             dbms_output.put_line
  222.             (
  223.             r1.table_name || ' - Warning: ' || TO_CHAR (v_skipped_columns) ||
  224.             ' LOB or LONG columns were omitted from the comparison'
  225.             );
  226.             v_warning_count := v_warning_count + 1;
  227.           END IF;
  228.           --
  229.           -- Next give the user a query they could run to see all of the
  230.           -- differing data between the two tables. To prepare the query,
  231.           -- first we'll break the list of columns in the table into smaller
  232.           -- chunks, each short enough to fit on one line of a telnet window
  233.           -- without wrapping.
  234.           --
  235.           v_pos := 1;
  236.           v_piece_count := 0;
  237.           v_length := LENGTH (v_column_list);
  238.           LOOP
  239.             EXIT WHEN v_pos = v_length;
  240.             v_piece_count := v_piece_count + 1;
  241.             IF v_length - v_pos < 72 THEN
  242.               v_column_pieces(v_piece_count) := SUBSTR (v_column_list, v_pos);
  243.               v_pos := v_length;
  244.             ELSE
  245.               v_next_break :=
  246.                 GREATEST (INSTR (SUBSTR (v_column_list, 1, v_pos + 72),
  247.                                  ',"', -1),
  248.                           INSTR (SUBSTR (v_column_list, 1, v_pos + 72),
  249.                                  ',/* "', -1),
  250.                           INSTR (SUBSTR (v_column_list, 1, v_pos + 72),
  251.                                  ' /* "', -1));
  252.               v_column_pieces(v_piece_count) :=
  253.                 SUBSTR (v_column_list, v_pos, v_next_break - v_pos + 1);
  254.               v_pos := v_next_break + 1;
  255.             END IF;
  256.           END LOOP;
  257.           dbms_output.put_line ('Use the following query to view the data ' ||
  258.                                 'discrepencies:');
  259.           dbms_output.put_line ('(');
  260.           dbms_output.put_line ('SELECT ''Local'' "LOCATION",');
  261.           FOR i IN 1..v_piece_count LOOP
  262.             dbms_output.put_line (v_column_pieces(i));
  263.           END LOOP;
  264.           dbms_output.put_line ('FROM "' || r1.table_name || '"');
  265.           dbms_output.put_line ('MINUS');
  266.           dbms_output.put_line ('SELECT ''Local'' "LOCATION",');
  267.           FOR i IN 1..v_piece_count LOOP
  268.             dbms_output.put_line (v_column_pieces(i));
  269.           END LOOP;
  270.           dbms_output.put_line ('FROM "' || r1.table_name || '"@&dblink');
  271.           dbms_output.put_line (') UNION ALL (');
  272.           dbms_output.put_line ('SELECT ''Remote'' "LOCATION",');
  273.           FOR i IN 1..v_piece_count LOOP
  274.             dbms_output.put_line (v_column_pieces(i));
  275.           END LOOP;
  276.           dbms_output.put_line ('FROM "' || r1.table_name || '"@&dblink');
  277.           dbms_output.put_line ('MINUS');
  278.           dbms_output.put_line ('SELECT ''Remote'' "LOCATION",');
  279.           FOR i IN 1..v_piece_count LOOP
  280.             dbms_output.put_line (v_column_pieces(i));
  281.           END LOOP;
  282.           dbms_output.put_line ('FROM "' || r1.table_name || '"');
  283.           dbms_output.put_line (');');
  284.           v_diff_count := v_diff_count + 1;
  285.         END IF;
  286.       EXCEPTION
  287.         WHEN OTHERS THEN
  288.           --
  289.           -- An error occurred while processing this table. (Most likely it
  290.           -- doesn't exist or has fewer columns on the remote database.)
  291.           -- Show the error we encountered on the report.
  292.           --
  293.           dbms_output.put_line (r1.table_name || ' - ' || SQLERRM);
  294.           v_error_count := v_error_count + 1;
  295.       END;
  296.     END IF;
  297.   END LOOP;
  298.   --
  299.   -- Print summary information.
  300.   --
  301.   dbms_output.put_line ('-------------------------------------------------');
  302.   dbms_output.put_line
  303.   (
  304.   'Tables examined: ' || TO_CHAR (v_same_count + v_diff_count + v_error_count)
  305.   );
  306.   dbms_output.put_line
  307.   (
  308.   'Tables with data discrepencies: ' || TO_CHAR (v_diff_count)
  309.   );
  310.   IF v_warning_count > 0 THEN
  311.     dbms_output.put_line
  312.     (
  313.     'Tables with warnings: ' || TO_CHAR(v_warning_count)
  314.     );
  315.   END IF;
  316.   IF v_error_count > 0 THEN
  317.     dbms_output.put_line
  318.     (
  319.     'Tables that could not be checked due to errors: ' || TO_CHAR(v_error_count)
  320.     );
  321.   END IF;
  322.   dbms_sql.close_cursor (v_cursor);
  323. END;
  324. /
  325.  
Copyright GeekInterview.com


Next: Converting Rows to Columns


 

Latest Code Samples

 

Popular Code Samples

 

Related Code Samples

 

Post Comment


Members Please Login

Name:  Email: (Optional. Used for Notification)

Title:
 
Comment:
Validation Code: <=>  (Enter this code in text box)





Popular Coders

# Coder NameHits
1. jamesravid16273
2. Jim.Anderson8828
3. krishnaindia20078132
4. Mohit Sharma6752
5. Beena5371
6. jainsourabh24062
7. SriramKrishna1856
8. Satheesh1778

Active Coders

Refined Tags

 

Sponsored Links

 
About Us -  Privacy Policy -  Terms and Conditions -  Contact  

Copyright © 2005 - 2009 GeekInterview.com. All Rights Reserved

Page copy protected against web site content infringement by Copyscape