| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- const fs = require('fs');
- // Load data
- const dbOverlapCols = JSON.parse(fs.readFileSync('d:/Workspaces/slaj/_db_overlap_cols.json', 'utf8'));
- const rohsTables = JSON.parse(fs.readFileSync('d:/Workspaces/slaj/_rohs_tables.json', 'utf8'));
- const dbAllNames = JSON.parse(fs.readFileSync('d:/Workspaces/slaj/_slaj_table_names.json', 'utf8'));
- // Normalize type for comparison
- function normType(t) {
- t = t.toUpperCase().trim().replace(/\s+/g, ' ');
- // Remove length specifications for comparison
- t = t.replace(/\(\d+(?:,\d+)?\)/g, '');
- // Map equivalent types
- const map = {
- 'BPCHAR': 'CHAR',
- 'VARCHAR': 'VARCHAR',
- 'NUMERIC': 'NUMERIC',
- 'DECIMAL': 'NUMERIC',
- 'INT4': 'INTEGER',
- 'INT': 'INTEGER',
- 'INT8': 'BIGINT',
- 'BIGINT': 'BIGINT',
- 'BOOL': 'BOOLEAN',
- 'FLOAT8': 'DOUBLE PRECISION',
- 'TIMESTAMPTZ': 'TIMESTAMP',
- 'TIMESTAMP': 'TIMESTAMP',
- 'DATE': 'DATE',
- 'TEXT': 'TEXT',
- 'BYTEA': 'BYTEA',
- 'FLOAT4': 'REAL',
- 'JSONB': 'JSONB',
- 'JSON': 'JSON',
- 'INT2': 'SMALLINT',
- 'SMALLINT': 'SMALLINT',
- };
- return map[t] || t;
- }
- // Categorize ROHS tables
- const skipPattern = /^(MLOG\$_|MV_|T_VWMS_)|_(BAK\d*$|MW\d*$|MW$|0731$|1125$|BAK25$|0326$)|_20250[47]\d{2}$|BAK2025|_2025011[03]$|_20250110$|_20250113$/;
- const rohsSkip = Object.keys(rohsTables).filter(t => skipPattern.test(t));
- const rohsReal = Object.keys(rohsTables).filter(t => !skipPattern.test(t));
- const rohsRealTables = {};
- rohsReal.forEach(t => { rohsRealTables[t] = rohsTables[t]; });
- // Map DB table names (lowercase) to ROHS names (uppercase)
- const dbLowerMap = {};
- dbAllNames.forEach(t => { dbLowerMap[t.toLowerCase()] = t; });
- // Classify all ROHS real tables
- const overlap = []; // Tables in both
- const rohsOnly = []; // ROHS tables not in DB
- const rohsBak = []; // ROHS backup/MV tables
- for (const t of Object.keys(rohsRealTables)) {
- const dbName = dbLowerMap[t.toLowerCase()];
- if (dbName) {
- overlap.push({rohs: t, db: dbName});
- } else {
- rohsOnly.push(t);
- }
- }
- for (const t of rohsSkip) {
- const dbName = dbLowerMap[t.toLowerCase()];
- rohsBak.push({rohs: t, inDb: !!dbName});
- }
- // Analyze each overlap table
- const fullMatch = [];
- const realDiff = [];
- const trivialTypeDiff = [];
- for (const o of overlap) {
- const rohsCols = rohsRealTables[o.rohs] || [];
- const dbCols = dbOverlapCols[o.db] || [];
- const rohsColMap = {};
- rohsCols.forEach(c => { rohsColMap[c.name] = c.type; });
- const dbColMap = {};
- dbCols.forEach(c => { dbColMap[c.name] = c.type; });
- const rohsNames = Object.keys(rohsColMap);
- const dbNames = Object.keys(dbColMap);
- const rohsOnlyCols = rohsNames.filter(n => !dbNames.includes(n));
- const dbOnlyCols = dbNames.filter(n => !rohsNames.includes(n));
- const common = rohsNames.filter(n => dbNames.includes(n));
- // Check real type differences (after normalization)
- const realTypeDiffs = [];
- const trivialDiffs = [];
- for (const cn of common) {
- const rt = normType(rohsColMap[cn]);
- const dt = normType(dbColMap[cn]);
- if (rt !== dt) {
- realTypeDiffs.push({col: cn, rohs: rohsColMap[cn], db: dbColMap[cn], rohsNorm: rt, dbNorm: dt});
- } else if (rohsColMap[cn] !== dbColMap[cn]) {
- trivialDiffs.push({col: cn, rohs: rohsColMap[cn], db: dbColMap[cn]});
- }
- }
- if (rohsOnlyCols.length === 0 && dbOnlyCols.length === 0 && realTypeDiffs.length === 0) {
- fullMatch.push({...o, trivialDiffs: trivialDiffs.length});
- } else {
- realDiff.push({
- ...o,
- rohsOnlyCols,
- dbOnlyCols,
- realTypeDiffs,
- trivialDiffs: trivialDiffs.length,
- });
- }
- }
- // ======== REPORT ========
- console.log('========================================');
- console.log(' 六项机制(ROHS) 与 安监(slaj) 数据库对比分析报告');
- console.log('========================================\n');
- console.log('【总体概况】');
- console.log(` ROHS SQL文件中表总数: ${Object.keys(rohsTables).length}`);
- console.log(` ROHS 真实业务表: ${Object.keys(rohsRealTables).length}`);
- console.log(` ROHS 备份/物化视图/日志表: ${rohsSkip.length}`);
- console.log(` 安监 slaj schema 表总数: ${dbAllNames.length}`);
- console.log(` 重叠表 (两库都有): ${overlap.length}`);
- console.log(` ROHS独有表 (安监中没有): ${rohsOnly.length}`);
- console.log(` 安监独有表 (ROHS中没有): ${dbAllNames.length - overlap.length}`);
- console.log(`\n【重叠表分析】(共 ${overlap.length} 张)`);
- console.log(` 字段完全一致: ${fullMatch.length}`);
- console.log(` 有结构性差异: ${realDiff.length}`);
- if (fullMatch.length > 0) {
- console.log(`\n --- 完全一致的表 (仅类型名写法不同) ---`);
- for (const m of fullMatch) {
- console.log(` ✓ ${m.rohs} = ${m.db} (${rohsRealTables[m.rohs].length} cols, ${m.trivialDiffs > 0 ? m.trivialDiffs + ' trivial type diffs' : 'exact match'})`);
- }
- }
- if (realDiff.length > 0) {
- console.log(`\n --- 有真实差异的表 ---`);
- for (const m of realDiff) {
- const issues = [];
- if (m.rohsOnlyCols.length) issues.push(`ROHS独有字段: [${m.rohsOnlyCols.join(', ')}]`);
- if (m.dbOnlyCols.length) issues.push(`DB独有字段: [${m.dbOnlyCols.join(', ')}]`);
- for (const td of m.realTypeDiffs) {
- issues.push(`${td.col}: ROHS=${td.rohs} vs DB=${td.db}`);
- }
- const sev = (m.rohsOnlyCols.length + m.dbOnlyCols.length + m.realTypeDiffs.length);
- const icon = m.dbOnlyCols.length + m.rohsOnlyCols.length === 0 && m.realTypeDiffs.every(d => d.col === 'GUID' && d.rohs === 'CHAR(32)' && d.db === 'BPCHAR') ? '~' : '⚠';
- console.log(` ${icon} ${m.rohs} (${rohsRealTables[m.rohs].length}c) <-> ${m.db} (${Object.keys(dbOverlapCols[m.db]||{}).length}c): ${issues.join('; ')}`);
- }
- }
- console.log(`\n【ROHS独有表 - 安监中不存在的新表】(共 ${rohsOnly.length} 张)`);
- // Categorize ROHS-only tables
- const categoryMap = {
- 'SYS_': '系统管理类',
- 'T_BUSI_': '业务类',
- 'T_DICT_': '字典类',
- 'T_CON_': '配置类',
- 'T_SSO_': 'SSO单点登录类',
- 'T_VWMS_': 'VWMS类',
- 'ATT_': '附件/属性类',
- 'BIS_': '业务信息类',
- 'OBJ_': '对象类',
- 'REL_': '关系类',
- 'BDMS_': 'BDMS类',
- 'HARD_': '硬件类',
- 'HAZARD_': '危险源类',
- 'HIDD_': '隐患类',
- 'PPRTY_': '产权类',
- };
- const cats = {};
- for (const t of rohsOnly) {
- let cat = '其他';
- for (const [prefix, label] of Object.entries(categoryMap)) {
- if (t.startsWith(prefix)) { cat = label; break; }
- }
- if (!cats[cat]) cats[cat] = [];
- cats[cat].push(t);
- }
- for (const [cat, tables] of Object.entries(cats).sort()) {
- console.log(`\n [${cat}] (${tables.length}张):`);
- tables.sort().forEach(t => {
- const cols = rohsRealTables[t] || [];
- console.log(` ${t} (${cols.length} cols)`);
- });
- }
- console.log(`\n【ROHS备份/日志/MV表】(共 ${rohsSkip.length} 张)`);
- for (const t of rohsBak) {
- console.log(` ${t.rohs} (${(rohsTables[t.rohs]||[]).length} cols) ${t.inDb ? '← 安监中也存在' : '(安监中不存在)'}`);
- }
- console.log(`\n========================================`);
- console.log('【合并可行性分析】');
- console.log('========================================');
- // Count by severity
- const critDiffs = realDiff.filter(m => m.rohsOnlyCols.length > 0 || m.dbOnlyCols.length > 0 || m.realTypeDiffs.some(d => d.rohsNorm !== d.dbNorm));
- const minorDiffs = realDiff.filter(m => !critDiffs.includes(m));
- console.log(`
- 1. 重叠表 (${overlap.length}张):
- - 完全一致 (仅CHAR/BPCHAR, VARCHAR长度等PG写法差异): ${fullMatch.length}张
- - 有轻微信赖差异 (类型兼容): ${realDiff.length - critDiffs.length}张
- - 有真实差异需处理: ${critDiffs.length}张
- 2. 新表 (ROHS独有, ${rohsOnly.length}张):
- - 这些表可以直接在安监数据库中创建
- - 涉及:${Object.keys(cats).join('、')}
- 3. 合并建议:
- - 重叠表:由于重叠表字段基本一致(差异主要是PG类型名写法不同和STR_TO_DATE<->TO_DATE),
- 这些表结构上可以直接兼容,不需要修改
- - ROHS独有的${rohsOnly.length}张表需要在安监数据库中新建
- - 注意:ROHS表的schema是 SLAJ_ROHS,安监的schema是 slaj,
- 合并时需要统一schema或者处理好跨schema访问
- 4. 风险点:`);
- // Find critical diffs
- for (const m of realDiff) {
- const issues = [];
- if (m.rohsOnlyCols.length) issues.push(`ROHS多出的列: ${m.rohsOnlyCols.join(', ')}`);
- if (m.dbOnlyCols.length) issues.push(`DB多出的列: ${m.dbOnlyCols.join(', ')}`);
- for (const td of m.realTypeDiffs) {
- if (td.rohsNorm !== td.dbNorm) {
- issues.push(`类型不兼容: ${td.col} ROHS=${td.rohs}(${td.rohsNorm}) vs DB=${td.db}(${td.dbNorm})`);
- }
- }
- if (issues.length) {
- console.log(` - ${m.rohs}: ${issues.join('; ')}`);
- }
- }
- console.log(`\n报告完毕。`);
|