更新 sql_diff.py
feat(sql_diff): 增强SQL差异分析功能以支持约束检测 扩展表结构解析功能,支持提取约束信息 修改比较逻辑,新增约束差异检测 更新SQL生成和输出显示,包含约束信息
This commit is contained in:
142
sql_diff.py
142
sql_diff.py
@@ -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("未发现差异")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user