From 242ef45c0fac19cff7d296bbec23694dfa2147c8 Mon Sep 17 00:00:00 2001 From: huababa1 <2037205722@qq.com> Date: Tue, 15 Jul 2025 04:49:02 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E3=80=91mysql?= =?UTF-8?q?=E5=87=BA=E9=A2=98=E5=90=8E=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../getpoints/ExamGetPointsServiceImpl.java | 685 +++++++++++++++++- 1 file changed, 660 insertions(+), 25 deletions(-) diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/service/getpoints/ExamGetPointsServiceImpl.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/service/getpoints/ExamGetPointsServiceImpl.java index 89651425..e0538230 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/service/getpoints/ExamGetPointsServiceImpl.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/service/getpoints/ExamGetPointsServiceImpl.java @@ -1,5 +1,6 @@ package pc.exam.pp.module.judgement.controller.service.getpoints; +import com.alibaba.excel.write.metadata.RowData; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -41,7 +42,10 @@ import java.nio.file.Paths; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; @Service @Slf4j @@ -183,16 +187,590 @@ public class ExamGetPointsServiceImpl implements ExamGetPointsService{ @Override public List get_mysql_point(PointsVo pointsVo) throws IOException { - - // 获取平台文件参数 ConfigDO config = configService.getConfigByKey("file_down_path"); + String sthPath = ZipUtil.downloadStudentFile(pointsVo.getShucaiPath(), config.getValue()); + String answerPath = ZipUtil.downloadStudentFile(pointsVo.getAnswerPath(), config.getValue()); + File zipStu = new File(sthPath); + File zipAnswer = new File(answerPath); + String stuFilePath = ZipUtil.unzipToNamedFolder(sthPath); + String answerFilePath = ZipUtil.unzipToNamedFolder(answerPath); + File zipStuFile = new File(stuFilePath); + File zipAnswerFile = new File(answerFilePath); + // 读取文件内容 + String stuSqlContent = readFileContentAutoCharset(getFirstMydFilePath(stuFilePath)); + String answerSqlContent = readFileContentAutoCharset(getFirstMydFilePath(answerFilePath)); - String sthPath = ZipUtil.downloadStudentFile(pointsVo.getAnswerPath(), config.getValue()); - List sqlStatements = readSQLFromFile(sthPath); - File zip_file = new File(sthPath); - zip_file.delete(); - return sqlStatements; + // 解析SQL语句 + Map stuTables = parseCreateTableStatements(stuSqlContent); + Map answerTables = parseCreateTableStatements(answerSqlContent); + + Map> stuInserts = parseInsertStatements(stuSqlContent); + Map> answerInserts = parseInsertStatements(answerSqlContent); + + List resultSqls = new ArrayList<>(); + // ✅ 直接提取视图语句 + List answerViews = extractCreateViewStatements(answerSqlContent); + resultSqls.addAll(answerViews); + // 1. 处理CREATE TABLE和ALTER TABLE差异 + // 你之前的代码段里:处理CREATE TABLE和ALTER TABLE差异的地方 + for (String tableName : answerTables.keySet()) { + TableInfo answerTable = answerTables.get(tableName); + TableInfo stuTable = stuTables.get(tableName); + + if (stuTable == null) { + // 学生表没有,直接返回完整答案建表语句 + resultSqls.add(answerTable.originalCreateSql); + } else { + // 学生表有,调用compareTableStructures对比并返回对应的SQL + List diffSqls = compareTableStructures(stuTable, answerTable); + resultSqls.addAll(diffSqls); + } + } + + + // 2. 处理INSERT差异 + for (String tableName : answerInserts.keySet()) { + List stuRows = stuInserts.getOrDefault(tableName, Collections.emptyList()); + List answerRows = answerInserts.get(tableName); + + // 建立主键索引(假设主键已通过create table解析得到,下面简化处理) + List primaryKeys = answerTables.containsKey(tableName) ? answerTables.get(tableName).primaryKeys : Collections.emptyList(); + + TableInfo stuTableInfo = stuTables.get(tableName); + if (stuTableInfo == null) { + // 如果学生表不存在,使用答案表结构 + stuTableInfo = answerTables.get(tableName); + if (stuTableInfo == null) { + throw new IllegalStateException("找不到表结构: " + tableName); + } + } + + // 假设你已经有这个多条合并的map函数和合并函数 + Map> stuRowsMapMulti = mapRowsByPrimaryKeyMulti(stuRows, primaryKeys, stuTableInfo); + Map> answerRowsMapMulti = mapRowsByPrimaryKeyMulti(answerRows, primaryKeys, stuTableInfo); + + // 答案有,学生没有,合并生成一条 insert 语句 + List insertRows = new ArrayList<>(); + if (stuRowsMapMulti == null || stuRowsMapMulti.isEmpty()) { + // 学生表完全为空,把答案表全加进去 + for (List rows : answerRowsMapMulti.values()) { + insertRows.addAll(rows); + } + } else { + // 否则按主键逐条比较 + for (String pk : answerRowsMapMulti.keySet()) { + if (!stuRowsMapMulti.containsKey(pk)) { + insertRows.addAll(answerRowsMapMulti.get(pk)); + } + } + } + + // 批量合并生成一条 insert + if (!insertRows.isEmpty()) { + TableInfo tableInfo = stuTables.get(tableName); + if (tableInfo == null) { + tableInfo = answerTables.get(tableName); + } + + if (tableInfo != null) { + List columns = new ArrayList<>(tableInfo.columns.keySet()); + String batchInsertSql = buildBatchInsert(tableName, columns, insertRows); + resultSqls.add(batchInsertSql); + } + } + // 学生有,答案没有,返回删除语句 + for (String pk : stuRowsMapMulti.keySet()) { + if (!answerRowsMapMulti.containsKey(pk)) { + List stuRowsList = stuRowsMapMulti.get(pk); + RowData mergedStuRow = mergeRowData(stuRowsList); + String deleteSql = generateDeleteSql(tableName, primaryKeys, mergedStuRow, stuTables.get(tableName)); + resultSqls.add(deleteSql); + } + } + + // 两边都有主键,内容不同,返回update语句 + for (String pk : answerRowsMapMulti.keySet()) { + if (stuRowsMapMulti.containsKey(pk)) { + List stuRowsList = stuRowsMapMulti.get(pk); + List answerRowsList = answerRowsMapMulti.get(pk); + + RowData mergedStuRow = mergeRowData(stuRowsList); + RowData mergedAnswerRow = mergeRowData(answerRowsList); + + if (!mergedStuRow.equalsContent(mergedAnswerRow)) { + String updateSql = generateUpdateSql(tableName, primaryKeys, mergedAnswerRow, mergedStuRow, stuTables.get(tableName)); + if (!updateSql.isEmpty()) { + resultSqls.add(updateSql); + } + } + } + } + + } + + // 3. 从answerFilePath目录下读取所有.sql文件内容,加入resultSqls + Path answerDir = Paths.get(answerFilePath); + if (Files.exists(answerDir) && Files.isDirectory(answerDir)) { + try (Stream paths = Files.walk(answerDir)) { + paths.filter(p -> Files.isRegularFile(p) && p.toString().toLowerCase().endsWith(".sql")) + .forEach(sqlFile -> { + try { + String sql = Files.readString(sqlFile); + if (sql != null && !sql.trim().isEmpty()) { + resultSqls.add(sql.trim()); + } + } catch (IOException e) { + // 读取某文件失败,记录日志或忽略 + System.err.println("读取SQL文件失败:" + sqlFile + ",原因:" + e.getMessage()); + } + }); + } + } + + zipStu.delete(); + zipAnswer.delete(); + deleteFolder(zipStuFile); + deleteFolder(zipAnswerFile); + return resultSqls; } + public static class TableInfo { + String tableName; + String originalCreateSql; + LinkedHashMap columns = new LinkedHashMap<>(); + List primaryKeys = new ArrayList<>(); + } + public static Set diffFields(List values1, List values2) { + Set diffIndexes = new HashSet<>(); + int size = Math.min(values1.size(), values2.size()); + for (int i = 0; i < size; i++) { + if (!Objects.equals(values1.get(i), values2.get(i))) { + diffIndexes.add(i); + } + } + return diffIndexes; + } + + + public static class ColumnInfo { + String name; + String typeDefinition; + boolean isPrimaryKey; + } + /** + * 获取目录下第一个 .myd 文件绝对路径 + */ + private String getFirstMydFilePath(String dirPath) { + File dir = new File(dirPath, "db"); + if (dir.exists() && dir.isDirectory()) { + File[] files = dir.listFiles((d, name) -> name.toLowerCase().endsWith(".myd")); + if (files != null && files.length > 0) { + return files[0].getAbsolutePath(); + } + } + return dirPath; // fallback + } + + private Map parseCreateTableStatements(String sqlContent) { + Map tableMap = new HashMap<>(); + + // 提取所有 CREATE TABLE ... 语句 + Pattern createTablePattern = Pattern.compile( + "CREATE TABLE\\s+`?(\\w+)`?\\s*\\((.*?)\\)\\s*ENGINE\\s*=.*?;", + Pattern.CASE_INSENSITIVE | Pattern.DOTALL + ); + + + Matcher matcher = createTablePattern.matcher(sqlContent); + + while (matcher.find()) { + String tableName = matcher.group(1); + String columnsSection = matcher.group(2); + String originalSql = matcher.group(0); + + TableInfo tableInfo = new TableInfo(); + tableInfo.tableName = tableName; + tableInfo.originalCreateSql = originalSql; + + // 按行解析字段和主键 + String[] lines = columnsSection.split(",\\s*\\n|,\\s*`"); // 支持多行或紧凑字段 + for (String line : lines) { + line = line.trim(); + if (line.isEmpty()) continue; + + if (line.toUpperCase().startsWith("PRIMARY KEY")) { + // 提取主键 + Pattern pkPattern = Pattern.compile("\\(([^)]+)\\)"); + Matcher pkMatcher = pkPattern.matcher(line); + if (pkMatcher.find()) { + String pkCols = pkMatcher.group(1); + for (String pk : pkCols.replace("`", "").split(",")) { + tableInfo.primaryKeys.add(pk.trim()); + } + } + } else if (line.startsWith("`")) { + // 普通字段 + String[] parts = line.split("\\s+", 3); + String columnName = parts[0].replace("`", ""); + String typeDefinition = parts.length > 1 ? parts[1] : "VARCHAR(255)"; + + ColumnInfo columnInfo = new ColumnInfo(); + columnInfo.name = columnName; + columnInfo.typeDefinition = typeDefinition; + columnInfo.isPrimaryKey = tableInfo.primaryKeys.contains(columnName); + + tableInfo.columns.put(columnName, columnInfo); + } + } + + tableMap.put(tableName, tableInfo); + } + + return tableMap; + } + private List extractCreateViewStatements(String sqlContent) { + List views = new ArrayList<>(); + Pattern createViewPattern = Pattern.compile( + "CREATE\\s+(?:ALGORITHM\\s*=\\s*.*?\\s+)?VIEW\\s+`?(\\w+)`?\\s+AS\\s+.*?;", + Pattern.CASE_INSENSITIVE | Pattern.DOTALL + ); + + Matcher viewMatcher = createViewPattern.matcher(sqlContent); + while (viewMatcher.find()) { + views.add(viewMatcher.group(0).trim()); + } + return views; + } + + private Map> parseInsertStatements(String sqlContent) { + Map> tableInserts = new HashMap<>(); + + // 只支持标准 INSERT INTO `table` VALUES (...) 语法 + Pattern insertPattern = Pattern.compile( + "INSERT INTO\\s+`?(\\w+)`?\\s+VALUES\\s*(\\(.*?\\));", + Pattern.CASE_INSENSITIVE | Pattern.DOTALL + ); + Matcher matcher = insertPattern.matcher(sqlContent); + + while (matcher.find()) { + String tableName = matcher.group(1); + String valuesSection = matcher.group(2); + String originalSql = matcher.group(0); + + // 拆分 values + List valuesList = parseValuesSection(valuesSection); + + RowData rowData = new RowData(valuesList, originalSql); + tableInserts.computeIfAbsent(tableName, k -> new ArrayList<>()).add(rowData); + } + + return tableInserts; + } + // 多条同主键数据按字段合并,非空优先 + public RowData mergeRowData(List rows) { + if (rows == null || rows.isEmpty()) return null; + int size = rows.get(0).values.size(); + List mergedValues = new ArrayList<>(Collections.nCopies(size, null)); + for (int i = 0; i < size; i++) { + for (RowData row : rows) { + String val = row.values.get(i); + if (val != null && !val.trim().isEmpty()) { + mergedValues.set(i, val); + break; + } + } + } + return new RowData(mergedValues); + } + + // 按主键分组,返回 Map> + public static Map> mapRowsByPrimaryKeyMulti(List rows, List primaryKeys, TableInfo table) { + Map> map = new HashMap<>(); + List columnsInOrder = new ArrayList<>(table.columns.keySet()); + for (RowData row : rows) { + StringBuilder keySb = new StringBuilder(); + for (String pk : primaryKeys) { + int idx = columnsInOrder.indexOf(pk); + if (idx >= 0 && idx < row.values.size()) { + keySb.append(row.values.get(idx)).append("|"); + } + } + String key = keySb.toString(); + map.computeIfAbsent(key, k -> new ArrayList<>()).add(row); + } + return map; + } + + /** + * 简单解析 VALUES 部分,按逗号拆分,去除引号、空格等 + */ + private List parseValuesSection(String valuesSection) { + List values = new ArrayList<>(); + + String content = valuesSection.trim(); + if (content.startsWith("(") && content.endsWith(")")) { + content = content.substring(1, content.length() - 1); + } + + // 粗略拆分(假设值中不包含逗号;实际情况复杂时用 SQL 解析器) + String[] parts = content.split(",(?=(?:[^']*'[^']*')*[^']*$)"); // 支持逗号分隔且忽略单引号包裹的逗号 + for (String part : parts) { + values.add(part.trim()); + } + + return values; + } + + public List compareTableStructures(TableInfo stuTable, TableInfo answerTable) { + List results = new ArrayList<>(); + + // 先判断答案表是否有学生表没有的字段 + boolean hasExtraColumn = false; + for (String col : answerTable.columns.keySet()) { + if (!stuTable.columns.containsKey(col)) { + hasExtraColumn = true; + break; + } + } + + if (hasExtraColumn) { + // 返回答案完整建表语句,替代学生建表 + results.add(answerTable.originalCreateSql); + } else { + // 否则对比字段属性,生成ALTER语句 + results.addAll(generateAlterTableSql(stuTable, answerTable)); + } + + return results; + } + + public static Map mapRowsByPrimaryKey(List rows, List primaryKeys, TableInfo table) { + Map map = new HashMap<>(); + + // 获取表的字段名按顺序组成的列表 + List columnsInOrder = new ArrayList<>(table.columns.keySet()); + + for (RowData row : rows) { + StringBuilder keySb = new StringBuilder(); + for (String pk : primaryKeys) { + int idx = columnsInOrder.indexOf(pk); // 用列名定位索引 + if (idx >= 0 && idx < row.values.size()) { + keySb.append(row.values.get(idx)).append("|"); + } + } + map.put(keySb.toString(), row); + } + return map; + } + + // 生成 ALTER TABLE 语句 + public List generateAlterTableSql(TableInfo stuTable, TableInfo answerTable) { + List alters = new ArrayList<>(); + String tableName = stuTable.tableName; + + // 遍历字段,对比字段类型或约束差异,生成 ALTER MODIFY COLUMN 语句 + for (String colName : answerTable.columns.keySet()) { + if (stuTable.columns.containsKey(colName)) { + ColumnInfo stuCol = stuTable.columns.get(colName); + ColumnInfo ansCol = answerTable.columns.get(colName); + + // 简单比较字段类型定义是否一致(大小写忽略) + if (!stuCol.typeDefinition.equalsIgnoreCase(ansCol.typeDefinition) || + stuCol.isPrimaryKey != ansCol.isPrimaryKey) { // 可以加更多属性判断 + alters.add(String.format("ALTER TABLE `%s` MODIFY COLUMN `%s` %s;", tableName, colName, ansCol.typeDefinition)); + } + } + } + + // 如果学生表字段比答案表多,删除多余字段 + for (String stuColName : stuTable.columns.keySet()) { + if (!answerTable.columns.containsKey(stuColName)) { + alters.add(String.format("ALTER TABLE `%s` DROP COLUMN `%s`;", tableName, stuColName)); + } + } + + return alters; + } + public static String buildInsertWithColumns(String tableName, List columns, List values) { + StringBuilder sb = new StringBuilder(); + sb.append("INSERT INTO `").append(tableName).append("` ("); + sb.append(columns.stream().map(col -> "`" + col + "`").collect(Collectors.joining(", "))); + sb.append(") VALUES ("); + sb.append(values.stream().map(val -> formatSqlValue(val)).collect(Collectors.joining(", "))); + sb.append(");"); + return sb.toString(); + } + + private static String formatSqlValue(String val) { + if (val == null || val.equalsIgnoreCase("null")) { + return "NULL"; + } + if (val.matches("^-?\\d+(\\.\\d+)?$")) { // 如果是数字,不加引号 + return val; + } + // 去除原始的引号(避免二次加引号) + if ((val.startsWith("'") && val.endsWith("'")) || (val.startsWith("\"") && val.endsWith("\""))) { + val = val.substring(1, val.length() - 1); + } + + val = val.replace("'", "''"); // SQL标准转义 + return "'" + val + "'"; // 添加单层引号 + } + + public static String buildBatchInsert(String tableName, List columns, List rows) { + StringBuilder sb = new StringBuilder(); + sb.append("INSERT INTO `").append(tableName).append("` ("); + sb.append(columns.stream().map(col -> "`" + col + "`").collect(Collectors.joining(", "))); + sb.append(") VALUES "); + + List valueTuples = new ArrayList<>(); + for (RowData row : rows) { + List formattedValues = new ArrayList<>(); + for (Object value : row.values) { + if (value == null) { + formattedValues.add("NULL"); + } else { + String valueStr = value.toString(); + // 去掉首尾引号(如果有) + if ((valueStr.startsWith("'") && valueStr.endsWith("'")) || + (valueStr.startsWith("\"") && valueStr.endsWith("\""))) { + valueStr = valueStr.substring(1, valueStr.length() - 1); + } + // 转义单引号 + valueStr = valueStr.replace("'", "''"); + formattedValues.add("'" + valueStr + "'"); + } + } + valueTuples.add("(" + String.join(", ", formattedValues) + ")"); + } + + sb.append(String.join(", ", valueTuples)); + sb.append(";"); + return sb.toString(); + } + + + public static String generateDeleteSql(String tableName, List primaryKeys, RowData stuRow, TableInfo tableInfo) { + StringBuilder where = new StringBuilder(); + List columnsInOrder = new ArrayList<>(tableInfo.columns.keySet()); + + for (int i = 0; i < primaryKeys.size(); i++) { + String pk = primaryKeys.get(i); + int idx = columnsInOrder.indexOf(pk); + String val = stuRow.values.get(idx); + + if (i > 0) where.append(" AND "); + where.append(String.format("`%s` = %s", pk, val)); + } + return String.format("DELETE FROM `%s` WHERE %s;", tableName, where.toString()); + } + + + // 生成 UPDATE 语句,更新全部非主键字段 + public static String generateUpdateSql(String tableName, List primaryKeys, RowData answerRow, RowData stuRow, TableInfo tableInfo) { + StringBuilder setClause = new StringBuilder(); + StringBuilder whereClause = new StringBuilder(); + + List columnsInOrder = new ArrayList<>(tableInfo.columns.keySet()); + + Set diffIndexes = diffFields(stuRow.values, answerRow.values); + + + for (int i = 0; i < columnsInOrder.size(); i++) { + String colName = columnsInOrder.get(i); + String value = answerRow.values.get(i); + + if (primaryKeys.contains(colName)) { + // 拼接WHERE + if (whereClause.length() > 0) whereClause.append(" AND "); + whereClause.append(String.format("`%s` = %s", colName, value)); + } else if (diffIndexes.contains(i)) { + // 拼接SET,只包含变动字段 + if (setClause.length() > 0) setClause.append(", "); + setClause.append(String.format("`%s` = %s", colName, value)); + } + } + + // 如果没有字段变动,返回空字符串或null + if (setClause.length() == 0) { + return null; + } + + return String.format("UPDATE `%s` SET %s WHERE %s;", tableName, setClause.toString(), whereClause.toString()); + } + + + + + public class RowData { + List values; // 每一列的值,按列顺序存储 + String originalInsertSql; // 原始 INSERT 语句 + + public RowData() { + } + + public RowData(List values, String originalInsertSql) { + this.values = values; + this.originalInsertSql = originalInsertSql; + + + } + + public RowData(List values) { + this.values = values; + } + + /** + * 比较两个 RowData 的字段值,返回值不同的字段索引列表 + */ + public List diffFields(RowData other) { + List diffIndexes = new ArrayList<>(); + int size = Math.min(this.values.size(), other.values.size()); + for (int i = 0; i < size; i++) { + String v1 = this.values.get(i); + String v2 = other.values.get(i); + if (v1 == null && v2 == null) { + continue; + } + if (v1 == null || v2 == null || !v1.equals(v2)) { + diffIndexes.add(i); + } + } + // 如果两者长度不同,可以考虑多出来的字段也算不同 + if (this.values.size() != other.values.size()) { + for (int i = size; i < Math.max(this.values.size(), other.values.size()); i++) { + diffIndexes.add(i); + } + } + return diffIndexes; + } + + /** + * 你原有的 equalsContent 可以保留,用于全字段对比 + */ + public boolean equalsContent(RowData other) { + if (this.values.size() != other.values.size()) { + return false; + } + return this.values.equals(other.values); + } + } + + + + // 自动识别 UTF-8 or GBK + private String readFileContentAutoCharset(String filePath) throws IOException { + try { + // 优先尝试 UTF-8 + return Files.readString(Paths.get(filePath), StandardCharsets.UTF_8); + } catch (MalformedInputException e) { + // 如果UTF-8失败,再尝试GBK + System.out.println("文件不是UTF-8编码,尝试使用GBK读取: " + filePath); + return Files.readString(Paths.get(filePath), Charset.forName("GBK")); + } + } + + + public static void deleteFolder(File folder) { if (folder.isDirectory()) { @@ -205,31 +783,88 @@ public class ExamGetPointsServiceImpl implements ExamGetPointsService{ } folder.delete(); // 删除空文件夹或文件 } - private static List readSQLFromFile(String filePath) throws IOException { + private List compareSqlFiles(String stuFilePath, String answerFilePath) throws IOException { + System.out.println("学生文件:" + stuFilePath); + System.out.println("答案文件:" + answerFilePath); + // 读取两个文件的SQL语句块集合 + Set stuSqlSet = readAllSqlFromFile(stuFilePath); + Set answerSqlSet = readAllSqlFromFile(answerFilePath); - List lines = readFileAutoCharset(filePath); - List sqlList = parseSql(lines); + System.out.println("学生SQL语句:"); + System.out.println(stuSqlSet); + System.out.println("答案SQL语句:"); + System.out.println(answerSqlSet); - for (String sql : sqlList) { - System.out.println(sql); - System.out.println("-------"); - } + // 差集:学生文件中有而标准答案没有的SQL语句 + Set diff = new LinkedHashSet<>(stuSqlSet); + diff.removeAll(answerSqlSet); - return sqlList; + return new ArrayList<>(diff); } - // 自动识别 UTF-8 or GBK - private static List readFileAutoCharset(String filePath) throws IOException { - try { - // 优先尝试 UTF-8 - return Files.readAllLines(Paths.get(filePath), Charset.forName("UTF-8")); - } catch (MalformedInputException e) { - // 如果UTF-8失败,再尝试GBK - System.out.println("文件不是UTF-8编码,尝试使用GBK编码读取..."); - return Files.readAllLines(Paths.get(filePath), Charset.forName("GBK")); - } + private Set readAllSqlFromFile(String filePath) throws IOException { + Set sqlSet = new LinkedHashSet<>(); + + String content = readFileContentAutoCharset(filePath); + sqlSet.addAll(extractSqlStatements(content)); // 提取完整SQL块 + + return sqlSet; } + + private List extractSqlStatements(String fileContent) { + List result = new ArrayList<>(); + + // 清理注释 + fileContent = fileContent.replaceAll("(?s)/\\*.*?\\*/", ""); + fileContent = fileContent.replaceAll("(?m)--.*?$", ""); + + // 合并多行,方便用正则提取 + String normalizedContent = fileContent.replaceAll("\\r?\\n", "\n"); + + // 提取 CREATE TABLE ... ;(包括多行) + Matcher matcher = Pattern.compile("(?i)(CREATE TABLE[\\s\\S]*?;)").matcher(normalizedContent); + while (matcher.find()) { + String statement = matcher.group(1).trim(); + result.add(standardizeTableSql(statement)); // 标准化后加入 + } + + // 提取其他SQL语句 + String[] otherStatements = normalizedContent.split(";"); + for (String stmt : otherStatements) { + String statement = stmt.trim(); + if (statement.isEmpty()) continue; + + String upper = statement.length() >= 50 ? statement.substring(0, 50).toUpperCase() : statement.toUpperCase(); + + if (isCoreSqlBlock(upper) && !statement.startsWith("CREATE TABLE")) { + result.add(statement + ";"); + } + } + + return result; + } + + private String standardizeTableSql(String sql) { + // 去掉多余空白 + sql = sql.replaceAll("\\s+", " "); + return sql.trim(); + } + + private boolean isCoreSqlBlock(String sqlStart) { + return sqlStart.startsWith("CREATE TABLE") + || sqlStart.startsWith("CREATE OR REPLACE VIEW") + || sqlStart.startsWith("CREATE VIEW") + || sqlStart.startsWith("INSERT INTO") + || sqlStart.startsWith("UPDATE") + || sqlStart.startsWith("DELETE FROM") + || sqlStart.startsWith("ALTER TABLE"); // 可选:识别ALTER修改语句 + } + + + + + // 解析SQL:去掉注释,只保留SQL语句 private static List parseSql(List lines) { List sqlList = new ArrayList<>();