_db_compare.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. const { Client } = require('pg');
  2. const fs = require('fs');
  3. async function main() {
  4. const client = new Client({
  5. host: '39.98.38.2',
  6. port: 5866,
  7. database: 'highgo',
  8. user: 'highgo',
  9. password: 'Gw@141516',
  10. connectionTimeoutMillis: 30000,
  11. });
  12. try {
  13. await client.connect();
  14. console.log('Connected to database');
  15. // Step 1: Get all table names quickly
  16. const tableRes = await client.query(`
  17. SELECT table_name
  18. FROM information_schema.tables
  19. WHERE table_schema = 'slaj' AND table_type = 'BASE TABLE'
  20. ORDER BY table_name
  21. `);
  22. const dbTableNames = tableRes.rows.map(r => r.table_name);
  23. console.log(`Total tables in slaj schema: ${dbTableNames.length}`);
  24. // Save all table names first
  25. fs.writeFileSync('d:/Workspaces/slaj/_slaj_table_names.json', JSON.stringify(dbTableNames, null, 2));
  26. console.log('Saved table names to _slaj_table_names.json');
  27. // Step 2: Load ROHS table names
  28. const rohsRaw = JSON.parse(fs.readFileSync('d:/Workspaces/slaj/_rohs_tables.json', 'utf8'));
  29. const rohsNames = Object.keys(rohsRaw);
  30. // Find overlap - case insensitive comparison
  31. // ROHS tables are uppercase, DB tables could be mixed case
  32. const dbUpperMap = {};
  33. dbTableNames.forEach(t => { dbUpperMap[t.toUpperCase()] = t; });
  34. const overlap = [];
  35. const rohsOnly = [];
  36. const dbOnly = [];
  37. for (const rt of rohsNames) {
  38. if (dbUpperMap[rt.toUpperCase()]) {
  39. overlap.push({rohs: rt, db: dbUpperMap[rt.toUpperCase()]});
  40. } else {
  41. rohsOnly.push(rt);
  42. }
  43. }
  44. console.log(`\nOverlap tables: ${overlap.length}`);
  45. console.log(`ROHS-only tables: ${rohsOnly.length}`);
  46. console.log(`DB-only tables: ${dbTableNames.length - overlap.length}`);
  47. // Step 3: For overlapping tables, fetch DB column details
  48. const overlapDbNames = overlap.map(o => o.db);
  49. console.log(`\nFetching columns for ${overlapDbNames.length} overlapping tables...`);
  50. const dbOverlapCols = {};
  51. for (let i = 0; i < overlapDbNames.length; i++) {
  52. const tname = overlapDbNames[i];
  53. const colRes = await client.query(`
  54. SELECT column_name, data_type,
  55. COALESCE(character_maximum_length, numeric_precision) AS max_length,
  56. is_nullable, column_default,
  57. udt_name
  58. FROM information_schema.columns
  59. WHERE table_schema = 'slaj' AND table_name = $1
  60. ORDER BY ordinal_position
  61. `, [tname]);
  62. dbOverlapCols[tname] = colRes.rows.map(c => ({
  63. name: c.column_name.toUpperCase(),
  64. type: c.udt_name ? c.udt_name.toUpperCase() : c.data_type.toUpperCase(),
  65. nullable: c.is_nullable === 'YES',
  66. default: c.column_default,
  67. }));
  68. if ((i+1) % 20 === 0) console.log(` Fetched ${i+1}/${overlapDbNames.length}`);
  69. }
  70. // Save overlap columns
  71. fs.writeFileSync('d:/Workspaces/slaj/_db_overlap_cols.json', JSON.stringify(dbOverlapCols, null, 2));
  72. console.log(`Saved overlap columns to _db_overlap_cols.json`);
  73. // Step 4: Do detailed comparison
  74. let matchCount = 0;
  75. let mismatchCount = 0;
  76. const mismatches = [];
  77. for (const o of overlap) {
  78. const rohsCols = rohsRaw[o.rohs] || [];
  79. const dbCols = dbOverlapCols[o.db] || [];
  80. const rohsColNames = rohsCols.map(c => c.name);
  81. const dbColNames = dbCols.map(c => c.name);
  82. const rohsOnlyCols = rohsColNames.filter(n => !dbColNames.includes(n));
  83. const dbOnlyCols = dbColNames.filter(n => !rohsColNames.includes(n));
  84. const commonCols = rohsColNames.filter(n => dbColNames.includes(n));
  85. // Compare types of common columns
  86. const typeDiffs = [];
  87. for (const cn of commonCols) {
  88. const rohsType = (rohsCols.find(c => c.name === cn) || {}).type || '';
  89. const dbType = (dbCols.find(c => c.name === cn) || {}).type || '';
  90. if (rohsType !== dbType) {
  91. typeDiffs.push({col: cn, rohs: rohsType, db: dbType});
  92. }
  93. }
  94. const isMatch = rohsOnlyCols.length === 0 && dbOnlyCols.length === 0 && typeDiffs.length === 0;
  95. if (isMatch) {
  96. matchCount++;
  97. } else {
  98. mismatchCount++;
  99. mismatches.push({
  100. rohs: o.rohs,
  101. db: o.db,
  102. rohsOnlyCols,
  103. dbOnlyCols,
  104. typeDiffs,
  105. commonCount: commonCols.length,
  106. });
  107. }
  108. }
  109. // Generate report
  110. const report = {
  111. summary: {
  112. rohsTotalTables: rohsNames.length,
  113. dbTotalTables: dbTableNames.length,
  114. overlapCount: overlap.length,
  115. rohsOnlyCount: rohsOnly.length,
  116. dbOnlyCount: dbTableNames.length - overlap.length,
  117. fullMatchCount: matchCount,
  118. mismatchCount: mismatchCount,
  119. },
  120. mismatches,
  121. rohsOnly,
  122. overlapAll: overlap.map(o => ({rohs: o.rohs, db: o.db})),
  123. };
  124. fs.writeFileSync('d:/Workspaces/slaj/_comparison_report.json', JSON.stringify(report, null, 2));
  125. console.log(`\n=== COMPARISON SUMMARY ===`);
  126. console.log(`ROHS tables: ${rohsNames.length}`);
  127. console.log(`安监 DB tables: ${dbTableNames.length}`);
  128. console.log(`重叠表: ${overlap.length}`);
  129. console.log(`ROHS独有表: ${rohsOnly.length}`);
  130. console.log(`安监独有表: ${dbTableNames.length - overlap.length}`);
  131. console.log(`完全匹配: ${matchCount}`);
  132. console.log(`字段有差异: ${mismatchCount}`);
  133. console.log(`\n=== 字段有差异的表 ===`);
  134. for (const m of mismatches) {
  135. console.log(`\n ROHS: ${m.rohs} <-> DB: ${m.db}`);
  136. if (m.rohsOnlyCols.length) console.log(` ROHS独有字段: ${m.rohsOnlyCols.join(', ')}`);
  137. if (m.dbOnlyCols.length) console.log(` DB独有字段: ${m.dbOnlyCols.join(', ')}`);
  138. for (const td of m.typeDiffs) {
  139. console.log(` 类型差异 [${td.col}]: ROHS=${td.rohs} DB=${td.db}`);
  140. }
  141. }
  142. console.log(`\n=== ROHS独有表 (安监中不存在) ===`);
  143. rohsOnly.forEach(t => {
  144. console.log(` ${t} (${(rohsRaw[t]||[]).length} cols)`);
  145. });
  146. await client.end();
  147. console.log('\nDone! Full report saved to _comparison_report.json');
  148. } catch (err) {
  149. console.error('Error:', err.message);
  150. console.error(err.stack);
  151. process.exit(1);
  152. }
  153. }
  154. main();