更新 sql_diff.py

feat(sql_diff): 增强SQL差异分析功能以支持约束检测

扩展表结构解析功能,支持提取约束信息
修改比较逻辑,新增约束差异检测
更新SQL生成和输出显示,包含约束信息
This commit is contained in:
2026-01-26 17:05:10 +08:00
parent 25c03d643f
commit 7ed871da34

View File

@@ -46,7 +46,7 @@ def parse_sql_file(file_path):
"""
解析SQL文件提取表结构信息
:param file_path: SQL文件路径
:return: 表结构字典,格式为 {表名: {字段名: 字段定义}}
:return: 表结构字典,格式为 {表名: {'fields': {字段名: 字段定义}, 'constraints': [约束定义]}}
"""
tables = {}
@@ -58,18 +58,53 @@ def parse_sql_file(file_path):
matches = table_pattern.findall(content)
for table_name, table_content in matches:
# 解析字段定义
field_pattern = re.compile(r'\s*`(.*?)`\s+(.*?)(?:,|\s*$)', re.MULTILINE)
# 解析字段定义和约束
fields = {}
constraints = []
for field_match in field_pattern.finditer(table_content):
field_name = field_match.group(1)
field_def = field_match.group(2).strip()
# 排除约束行
if not any(keyword in field_def for keyword in ['PRIMARY KEY', 'UNIQUE KEY', 'KEY', 'INDEX']):
fields[field_name] = field_def
# 手动解析字段和约束,处理括号和引号的匹配
lines = table_content.split('\n')
current_field = None
current_def = []
tables[table_name] = fields
for line in lines:
line = line.strip()
if not line:
continue
# 检查是否是字段定义的开始
field_match = re.match(r'`(.*?)`\s+', line)
if field_match:
# 如果有当前正在处理的字段,先保存
if current_field:
field_def = ' '.join(current_def).strip()
fields[current_field] = field_def
# 开始处理新字段
current_field = field_match.group(1)
# 提取字段定义的开始部分
field_def_start = line[field_match.end():]
current_def = [field_def_start.rstrip(',').strip()]
elif any(keyword in line.upper() for keyword in ['PRIMARY KEY', 'UNIQUE KEY', 'KEY', 'INDEX']):
# 处理约束行
if current_field:
# 先保存之前的字段
field_def = ' '.join(current_def).strip()
fields[current_field] = field_def
current_field = None
current_def = []
# 保存约束
constraints.append(line.rstrip(',').strip())
elif current_field:
# 继续处理当前字段的定义
current_def.append(line.rstrip(',').strip())
# 保存最后一个字段
if current_field:
field_def = ' '.join(current_def).strip()
fields[current_field] = field_def
tables[table_name] = {'fields': fields, 'constraints': constraints}
return tables
@@ -79,11 +114,12 @@ def compare_tables(old_tables, new_tables):
比较两个表结构字典,找出差异
:param old_tables: 旧表结构字典
:param new_tables: 新表结构字典
:return: 差异字典,包含新增表新增字段
:return: 差异字典,包含新增表新增字段和新增约束
"""
diff = {
'new_tables': [], # 新增的表
'added_fields': [] # 新增的字段,格式为 (表名, 字段名, 字段定义)
'added_fields': [], # 新增的字段,格式为 (表名, 字段名, 字段定义)
'added_constraints': [] # 新增的约束,格式为 (表名, 约束定义)
}
# 找出新增的表
@@ -91,15 +127,54 @@ def compare_tables(old_tables, new_tables):
if table_name not in old_tables:
diff['new_tables'].append(table_name)
# 找出共同表中新增的字段
# 找出共同表中新增的字段和约束
for table_name in new_tables:
if table_name in old_tables:
old_fields = old_tables[table_name]
new_fields = new_tables[table_name]
old_fields = old_tables[table_name]['fields']
new_fields = new_tables[table_name]['fields']
old_constraints = old_tables[table_name]['constraints']
new_constraints = new_tables[table_name]['constraints']
# 比较字段
for field_name in new_fields:
if field_name not in old_fields:
diff['added_fields'].append((table_name, field_name, new_fields[field_name]))
# 比较约束
for constraint in new_constraints:
# 检查约束是否已存在
constraint_exists = False
# 对于主键,只需要检查是否存在主键约束
if 'PRIMARY KEY' in constraint.upper():
for old_constraint in old_constraints:
if 'PRIMARY KEY' in old_constraint.upper():
constraint_exists = True
break
else:
# 对于其他约束(如索引),提取约束名称进行检查
constraint_name = None
# 尝试提取索引名称
constraint_match = re.search(r'(?:KEY|INDEX)\s+`?([^`\s]+)`?', constraint)
if constraint_match:
constraint_name = constraint_match.group(1)
if constraint_name:
# 检查旧约束中是否存在同名索引
for old_constraint in old_constraints:
old_match = re.search(r'(?:KEY|INDEX)\s+`?([^`\s]+)`?', old_constraint)
if old_match and old_match.group(1) == constraint_name:
constraint_exists = True
break
else:
# 如果无法提取索引名称,进行完整匹配
if constraint in old_constraints:
constraint_exists = True
# 只添加不存在的约束
if not constraint_exists:
diff['added_constraints'].append((table_name, constraint))
return diff
@@ -140,7 +215,23 @@ def generate_update_sql(old_file, new_file, diff):
update_sql += alter_sql
update_sql += '\n'
if not diff['new_tables'] and not diff['added_fields']:
# 添加新增约束的ALTER TABLE语句
if diff['added_constraints']:
update_sql += "-- 新增约束\n\n"
for table_name, constraint in diff['added_constraints']:
# 构建ALTER TABLE语句
if constraint.upper().startswith('PRIMARY KEY'):
alter_sql = f"ALTER TABLE `{table_name}` ADD {constraint};\n"
elif constraint.upper().startswith('UNIQUE KEY'):
alter_sql = f"ALTER TABLE `{table_name}` ADD {constraint};\n"
elif constraint.upper().startswith('KEY') or constraint.upper().startswith('INDEX'):
alter_sql = f"ALTER TABLE `{table_name}` ADD {constraint};\n"
else:
alter_sql = f"ALTER TABLE `{table_name}` ADD {constraint};\n"
update_sql += alter_sql
update_sql += '\n'
if not diff['new_tables'] and not diff['added_fields'] and not diff['added_constraints']:
update_sql += "-- 未发现差异\n"
return update_sql
@@ -194,6 +285,7 @@ def main():
print(f"update.sql已生成: {out_file}")
print(f"新增表: {len(diff['new_tables'])}")
print(f"新增字段: {len(diff['added_fields'])}")
print(f"新增约束: {len(diff['added_constraints'])}")
# 显示差异详情
if diff['new_tables']:
@@ -206,7 +298,23 @@ def main():
for table, field, _ in diff['added_fields']:
print(f" - {table}.{field}")
if not diff['new_tables'] and not diff['added_fields']:
if diff['added_constraints']:
print("新增约束列表:")
for table, constraint in diff['added_constraints']:
# 提取约束名称(如果有)
constraint_name = ""
constraint_match = re.search(r'(?:KEY|INDEX)\s+`?(.*?)`?\s*\(', constraint)
if constraint_match:
constraint_name = constraint_match.group(1)
elif 'PRIMARY KEY' in constraint:
constraint_name = "PRIMARY KEY"
if constraint_name:
print(f" - {table}.{constraint_name}")
else:
print(f" - {table}: {constraint[:50]}...")
if not diff['new_tables'] and not diff['added_fields'] and not diff['added_constraints']:
print("未发现差异")