forked from lunanting/cangku
250 lines
7.5 KiB
JavaScript
250 lines
7.5 KiB
JavaScript
/**
|
||
* 数据库表头分析脚本
|
||
* 从每个表的每个字段提取3个示例值,用于分析字段实际含义
|
||
*
|
||
* 使用方式:
|
||
* node analyze-tables.js --host <host> --port <port> --db <database> --user <user> --password <password>
|
||
*
|
||
* 示例:
|
||
* node analyze-tables.js --host rm-xxx.sqlserver.rds.aliyuncs.com --port 1433 --db mydb --user admin --password 123456
|
||
*/
|
||
|
||
const sql = require('mssql');
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
// 解析命令行参数
|
||
function parseArgs() {
|
||
const args = process.argv.slice(2);
|
||
const config = {};
|
||
for (let i = 0; i < args.length; i += 2) {
|
||
const key = args[i].replace('--', '');
|
||
const value = args[i + 1];
|
||
config[key] = value;
|
||
}
|
||
return config;
|
||
}
|
||
|
||
// 需要分析的表列表
|
||
const TABLES = [
|
||
{ name: 'jst_goods_profit_kpi_items_afs', description: '业绩退款相关信息' },
|
||
{ name: 'jst_sku', description: '普通商品资料表' },
|
||
{ name: 'fys_shopInfo', description: '店铺信息' },
|
||
{ name: 'jst_order_express_details', description: '订单快递详情' },
|
||
{ name: 'fys_SkuDataLibrary_SpuConfig', description: '产品资料SPU配置' },
|
||
{ name: 'op_operManage', description: 'SPU负责人管理' },
|
||
{ name: 'op_TargetManagement', description: '商品指标管理' },
|
||
{ name: 'fys_Ticketing_install', description: '开票安装单' },
|
||
{ name: 'fys_Ticketing_install_item', description: '安装明细表' },
|
||
{ name: 'fys_jstFreightCost', description: '聚水潭运费' },
|
||
{ name: 'fys_jstFreightCostDetail', description: '聚水潭运费明细' },
|
||
{ name: 'pc_kfChatLog', description: '客服聊天记录' }
|
||
];
|
||
|
||
async function getCloudDbConfig() {
|
||
const args = parseArgs();
|
||
|
||
// 如果提供了命令行参数,使用命令行参数
|
||
if (args.host && args.db && args.user && args.password) {
|
||
return {
|
||
server: args.host,
|
||
port: parseInt(args.port || '1433'),
|
||
database: args.db,
|
||
user: args.user,
|
||
password: args.password,
|
||
options: {
|
||
encrypt: args.ssl === 'true',
|
||
trustServerCertificate: true,
|
||
connectTimeout: 30000,
|
||
}
|
||
};
|
||
}
|
||
|
||
// 否则从本地数据库获取配置
|
||
const mysql = require('mysql2/promise');
|
||
const localConfig = {
|
||
host: args.localHost || 'localhost',
|
||
port: parseInt(args.localPort || '3306'),
|
||
user: args.localUser || 'root',
|
||
password: args.localPassword || process.env.LOCAL_DB_PASSWORD || '',
|
||
database: args.localDb || 'shujuku2_system'
|
||
};
|
||
|
||
try {
|
||
const connection = await mysql.createConnection(localConfig);
|
||
const [rows] = await connection.execute(
|
||
'SELECT driver, host, port, database_name, username, password, `ssl` FROM database_configs WHERE is_default = 1 LIMIT 1'
|
||
);
|
||
await connection.end();
|
||
|
||
if (rows.length > 0) {
|
||
const config = rows[0];
|
||
console.log(` 从本地数据库获取到配置: ${config.host}:${config.port}/${config.database_name}`);
|
||
return {
|
||
server: config.host,
|
||
port: config.port || 1433,
|
||
database: config.database_name,
|
||
user: config.username,
|
||
password: config.password,
|
||
options: {
|
||
encrypt: config.ssl === 1,
|
||
trustServerCertificate: true,
|
||
connectTimeout: 30000,
|
||
}
|
||
};
|
||
}
|
||
throw new Error('未找到云数据库配置');
|
||
} catch (error) {
|
||
console.error('从本地数据库获取配置失败:', error.message);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
async function getTableColumns(pool, tableName) {
|
||
try {
|
||
const result = await pool.request().query(`
|
||
SELECT COLUMN_NAME, DATA_TYPE
|
||
FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_NAME = '${tableName}'
|
||
ORDER BY ORDINAL_POSITION
|
||
`);
|
||
return result.recordset;
|
||
} catch (error) {
|
||
console.error(`获取表 ${tableName} 的列信息失败:`, error.message);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
async function getSampleData(pool, tableName, columnName) {
|
||
try {
|
||
// 获取3个非空的示例值
|
||
const result = await pool.request().query(`
|
||
SELECT TOP 3 [${columnName}] as value
|
||
FROM [${tableName}]
|
||
WHERE [${columnName}] IS NOT NULL AND CAST([${columnName}] AS NVARCHAR(MAX)) != ''
|
||
ORDER BY NEWID()
|
||
`);
|
||
return result.recordset.map(r => {
|
||
const val = r.value;
|
||
// 处理不同类型的值
|
||
if (val instanceof Date) {
|
||
return val.toISOString().replace('T', ' ').substring(0, 19);
|
||
}
|
||
if (typeof val === 'string' && val.length > 100) {
|
||
return val.substring(0, 100) + '...';
|
||
}
|
||
return String(val);
|
||
});
|
||
} catch (error) {
|
||
return [`[错误: ${error.message.substring(0, 50)}]`];
|
||
}
|
||
}
|
||
|
||
async function analyzeTable(pool, tableInfo) {
|
||
console.log(`\n正在分析表: ${tableInfo.name} (${tableInfo.description})`);
|
||
|
||
const columns = await getTableColumns(pool, tableInfo.name);
|
||
if (columns.length === 0) {
|
||
return { ...tableInfo, columns: [], error: '无法获取列信息' };
|
||
}
|
||
|
||
const analyzedColumns = [];
|
||
for (const col of columns) {
|
||
process.stdout.write(` - ${col.COLUMN_NAME}...`);
|
||
const samples = await getSampleData(pool, tableInfo.name, col.COLUMN_NAME);
|
||
analyzedColumns.push({
|
||
name: col.COLUMN_NAME,
|
||
type: col.DATA_TYPE,
|
||
samples
|
||
});
|
||
console.log(' 完成');
|
||
}
|
||
|
||
return {
|
||
...tableInfo,
|
||
columns: analyzedColumns
|
||
};
|
||
}
|
||
|
||
function generateMarkdown(results) {
|
||
let md = `# 云数据库表头分析报告
|
||
|
||
> 生成时间: ${new Date().toLocaleString('zh-CN')}
|
||
>
|
||
> 本文档通过提取每个字段的3个示例值来帮助理解字段的实际含义
|
||
|
||
---
|
||
|
||
`;
|
||
|
||
for (const table of results) {
|
||
md += `## ${table.name}\n\n`;
|
||
md += `**描述**: ${table.description}\n\n`;
|
||
|
||
if (table.error) {
|
||
md += `**错误**: ${table.error}\n\n`;
|
||
continue;
|
||
}
|
||
|
||
md += `| 序号 | 字段名 | 数据类型 | 示例值1 | 示例值2 | 示例值3 | 推测含义 |\n`;
|
||
md += `|------|--------|----------|---------|---------|---------|----------|\n`;
|
||
|
||
table.columns.forEach((col, idx) => {
|
||
const s1 = col.samples[0] || '-';
|
||
const s2 = col.samples[1] || '-';
|
||
const s3 = col.samples[2] || '-';
|
||
// 转义管道符号
|
||
const escape = (str) => String(str).replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
||
md += `| ${idx + 1} | ${col.name} | ${col.type} | ${escape(s1)} | ${escape(s2)} | ${escape(s3)} | |\n`;
|
||
});
|
||
|
||
md += `\n---\n\n`;
|
||
}
|
||
|
||
return md;
|
||
}
|
||
|
||
async function main() {
|
||
console.log('=== 云数据库表头分析工具 ===\n');
|
||
|
||
let pool;
|
||
try {
|
||
// 获取云数据库配置
|
||
console.log('1. 获取云数据库配置...');
|
||
const config = await getCloudDbConfig();
|
||
console.log(` 连接到: ${config.server}:${config.port}/${config.database}`);
|
||
|
||
// 连接云数据库
|
||
console.log('\n2. 连接云数据库...');
|
||
pool = await sql.connect(config);
|
||
console.log(' 连接成功!');
|
||
|
||
// 分析每个表
|
||
console.log('\n3. 开始分析表...');
|
||
const results = [];
|
||
for (const tableInfo of TABLES) {
|
||
const result = await analyzeTable(pool, tableInfo);
|
||
results.push(result);
|
||
}
|
||
|
||
// 生成Markdown报告
|
||
console.log('\n4. 生成分析报告...');
|
||
const markdown = generateMarkdown(results);
|
||
const outputPath = path.join(__dirname, '../../docs/云数据库表头分析.md');
|
||
fs.writeFileSync(outputPath, markdown, 'utf8');
|
||
console.log(` 报告已保存到: ${outputPath}`);
|
||
|
||
console.log('\n=== 分析完成 ===');
|
||
|
||
} catch (error) {
|
||
console.error('\n错误:', error.message);
|
||
process.exit(1);
|
||
} finally {
|
||
if (pool) {
|
||
await pool.close();
|
||
}
|
||
}
|
||
}
|
||
|
||
main();
|