Accept Merge Request #142: (hyc -> master)

Merge Request: 【修改】mysql出题后端

Created By: @华允传
Accepted By: @华允传
URL: https://g-iswv8783.coding.net/p/education/d/pengchen-exam-java/git/merge/142
This commit is contained in:
华允传
2025-07-15 05:07:22 +08:00
committed by Coding

View File

@@ -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<String> 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<String> sqlStatements = readSQLFromFile(sthPath);
File zip_file = new File(sthPath);
zip_file.delete();
return sqlStatements;
// 解析SQL语句
Map<String, TableInfo> stuTables = parseCreateTableStatements(stuSqlContent);
Map<String, TableInfo> answerTables = parseCreateTableStatements(answerSqlContent);
Map<String, List<RowData>> stuInserts = parseInsertStatements(stuSqlContent);
Map<String, List<RowData>> answerInserts = parseInsertStatements(answerSqlContent);
List<String> resultSqls = new ArrayList<>();
// ✅ 直接提取视图语句
List<String> 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<String> diffSqls = compareTableStructures(stuTable, answerTable);
resultSqls.addAll(diffSqls);
}
}
// 2. 处理INSERT差异
for (String tableName : answerInserts.keySet()) {
List<RowData> stuRows = stuInserts.getOrDefault(tableName, Collections.emptyList());
List<RowData> answerRows = answerInserts.get(tableName);
// 建立主键索引假设主键已通过create table解析得到下面简化处理
List<String> 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<String, List<RowData>> stuRowsMapMulti = mapRowsByPrimaryKeyMulti(stuRows, primaryKeys, stuTableInfo);
Map<String, List<RowData>> answerRowsMapMulti = mapRowsByPrimaryKeyMulti(answerRows, primaryKeys, stuTableInfo);
// 答案有,学生没有,合并生成一条 insert 语句
List<RowData> insertRows = new ArrayList<>();
if (stuRowsMapMulti == null || stuRowsMapMulti.isEmpty()) {
// 学生表完全为空,把答案表全加进去
for (List<RowData> 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<String> 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<RowData> 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<RowData> stuRowsList = stuRowsMapMulti.get(pk);
List<RowData> 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<Path> 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<String, ColumnInfo> columns = new LinkedHashMap<>();
List<String> primaryKeys = new ArrayList<>();
}
public static Set<Integer> diffFields(List<String> values1, List<String> values2) {
Set<Integer> 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<String, TableInfo> parseCreateTableStatements(String sqlContent) {
Map<String, TableInfo> 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<String> extractCreateViewStatements(String sqlContent) {
List<String> 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<String, List<RowData>> parseInsertStatements(String sqlContent) {
Map<String, List<RowData>> 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<String> valuesList = parseValuesSection(valuesSection);
RowData rowData = new RowData(valuesList, originalSql);
tableInserts.computeIfAbsent(tableName, k -> new ArrayList<>()).add(rowData);
}
return tableInserts;
}
// 多条同主键数据按字段合并,非空优先
public RowData mergeRowData(List<RowData> rows) {
if (rows == null || rows.isEmpty()) return null;
int size = rows.get(0).values.size();
List<String> 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<String, List<RowData>>
public static Map<String, List<RowData>> mapRowsByPrimaryKeyMulti(List<RowData> rows, List<String> primaryKeys, TableInfo table) {
Map<String, List<RowData>> map = new HashMap<>();
List<String> 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<String> parseValuesSection(String valuesSection) {
List<String> 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<String> compareTableStructures(TableInfo stuTable, TableInfo answerTable) {
List<String> 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<String, RowData> mapRowsByPrimaryKey(List<RowData> rows, List<String> primaryKeys, TableInfo table) {
Map<String, RowData> map = new HashMap<>();
// 获取表的字段名按顺序组成的列表
List<String> 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<String> generateAlterTableSql(TableInfo stuTable, TableInfo answerTable) {
List<String> 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<String> columns, List<String> 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<String> columns, List<RowData> 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<String> valueTuples = new ArrayList<>();
for (RowData row : rows) {
List<String> 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<String> primaryKeys, RowData stuRow, TableInfo tableInfo) {
StringBuilder where = new StringBuilder();
List<String> 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<String> primaryKeys, RowData answerRow, RowData stuRow, TableInfo tableInfo) {
StringBuilder setClause = new StringBuilder();
StringBuilder whereClause = new StringBuilder();
List<String> columnsInOrder = new ArrayList<>(tableInfo.columns.keySet());
Set<Integer> 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<String> values; // 每一列的值,按列顺序存储
String originalInsertSql; // 原始 INSERT 语句
public RowData() {
}
public RowData(List<String> values, String originalInsertSql) {
this.values = values;
this.originalInsertSql = originalInsertSql;
}
public RowData(List<String> values) {
this.values = values;
}
/**
* 比较两个 RowData 的字段值,返回值不同的字段索引列表
*/
public List<Integer> diffFields(RowData other) {
List<Integer> 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<String> readSQLFromFile(String filePath) throws IOException {
private List<String> compareSqlFiles(String stuFilePath, String answerFilePath) throws IOException {
System.out.println("学生文件:" + stuFilePath);
System.out.println("答案文件:" + answerFilePath);
// 读取两个文件的SQL语句块集合
Set<String> stuSqlSet = readAllSqlFromFile(stuFilePath);
Set<String> answerSqlSet = readAllSqlFromFile(answerFilePath);
List<String> lines = readFileAutoCharset(filePath);
List<String> 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<String> diff = new LinkedHashSet<>(stuSqlSet);
diff.removeAll(answerSqlSet);
return sqlList;
return new ArrayList<>(diff);
}
// 自动识别 UTF-8 or GBK
private static List<String> 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<String> readAllSqlFromFile(String filePath) throws IOException {
Set<String> sqlSet = new LinkedHashSet<>();
String content = readFileContentAutoCharset(filePath);
sqlSet.addAll(extractSqlStatements(content)); // 提取完整SQL块
return sqlSet;
}
private List<String> extractSqlStatements(String fileContent) {
List<String> 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<String> parseSql(List<String> lines) {
List<String> sqlList = new ArrayList<>();