""" 全面检查 f_polic_file_field 表的关联关系 重点检查输入字段(field_type=1)和输出字段(field_type=2)与模板的关联情况 """ import pymysql import os import sys from typing import Dict, List, Tuple from collections import defaultdict # 设置输出编码为UTF-8 if sys.platform == 'win32': import io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') # 数据库连接配置 DB_CONFIG = { 'host': os.getenv('DB_HOST', '152.136.177.240'), 'port': int(os.getenv('DB_PORT', 5012)), 'user': os.getenv('DB_USER', 'finyx'), 'password': os.getenv('DB_PASSWORD', '6QsGK6MpePZDE57Z'), 'database': os.getenv('DB_NAME', 'finyx'), 'charset': 'utf8mb4' } TENANT_ID = 615873064429507639 def check_all_templates_field_relations(conn) -> Dict: """检查所有模板的字段关联情况""" cursor = conn.cursor(pymysql.cursors.DictCursor) print("\n" + "="*80) print("1. 检查所有模板的字段关联情况") print("="*80) # 获取所有启用的模板 cursor.execute(""" SELECT id, name, template_code FROM f_polic_file_config WHERE tenant_id = %s AND state = 1 ORDER BY name """, (TENANT_ID,)) templates = cursor.fetchall() # 获取每个模板关联的字段(按类型分组) cursor.execute(""" SELECT fc.id AS template_id, fc.name AS template_name, f.id AS field_id, f.name AS field_name, f.filed_code AS field_code, f.field_type FROM f_polic_file_config fc INNER JOIN f_polic_file_field fff ON fc.id = fff.file_id AND fc.tenant_id = fff.tenant_id INNER JOIN f_polic_field f ON fff.filed_id = f.id AND fff.tenant_id = f.tenant_id WHERE fc.tenant_id = %s AND fc.state = 1 AND fff.state = 1 AND f.state = 1 ORDER BY fc.name, f.field_type, f.name """, (TENANT_ID,)) relations = cursor.fetchall() # 按模板分组统计 template_stats = {} for template in templates: template_stats[template['id']] = { 'template_id': template['id'], 'template_name': template['name'], 'template_code': template.get('template_code'), 'input_fields': [], 'output_fields': [], 'input_count': 0, 'output_count': 0 } # 填充字段信息 for rel in relations: template_id = rel['template_id'] if template_id in template_stats: field_info = { 'field_id': rel['field_id'], 'field_name': rel['field_name'], 'field_code': rel['field_code'], 'field_type': rel['field_type'] } if rel['field_type'] == 1: template_stats[template_id]['input_fields'].append(field_info) template_stats[template_id]['input_count'] += 1 elif rel['field_type'] == 2: template_stats[template_id]['output_fields'].append(field_info) template_stats[template_id]['output_count'] += 1 # 打印统计信息 print(f"\n共找到 {len(templates)} 个启用的模板\n") templates_without_input = [] templates_without_output = [] templates_without_any = [] for template_id, stats in template_stats.items(): status = [] if stats['input_count'] == 0: status.append("缺少输入字段") templates_without_input.append(stats) if stats['output_count'] == 0: status.append("缺少输出字段") templates_without_output.append(stats) if stats['input_count'] == 0 and stats['output_count'] == 0: templates_without_any.append(stats) status_str = " | ".join(status) if status else "[OK] 正常" print(f" {stats['template_name']} (ID: {stats['template_id']})") print(f" 输入字段: {stats['input_count']} 个 | 输出字段: {stats['output_count']} 个 | {status_str}") return { 'template_stats': template_stats, 'templates_without_input': templates_without_input, 'templates_without_output': templates_without_output, 'templates_without_any': templates_without_any } def check_input_field_relations_detail(conn) -> Dict: """详细检查输入字段的关联情况""" cursor = conn.cursor(pymysql.cursors.DictCursor) print("\n" + "="*80) print("2. 详细检查输入字段的关联情况") print("="*80) # 获取所有启用的输入字段 cursor.execute(""" SELECT id, name, filed_code FROM f_polic_field WHERE tenant_id = %s AND field_type = 1 AND state = 1 ORDER BY name """, (TENANT_ID,)) input_fields = cursor.fetchall() # 获取每个输入字段关联的模板 cursor.execute(""" SELECT f.id AS field_id, f.name AS field_name, f.filed_code AS field_code, fc.id AS template_id, fc.name AS template_name FROM f_polic_field f INNER JOIN f_polic_file_field fff ON f.id = fff.filed_id AND f.tenant_id = fff.tenant_id INNER JOIN f_polic_file_config fc ON fff.file_id = fc.id AND fff.tenant_id = fc.tenant_id WHERE f.tenant_id = %s AND f.field_type = 1 AND f.state = 1 AND fff.state = 1 AND fc.state = 1 ORDER BY f.name, fc.name """, (TENANT_ID,)) input_field_relations = cursor.fetchall() # 按字段分组 field_template_map = defaultdict(list) for rel in input_field_relations: field_template_map[rel['field_id']].append({ 'template_id': rel['template_id'], 'template_name': rel['template_name'] }) print(f"\n共找到 {len(input_fields)} 个启用的输入字段\n") fields_without_relations = [] fields_with_relations = [] for field in input_fields: field_id = field['id'] templates = field_template_map.get(field_id, []) if not templates: fields_without_relations.append(field) print(f" [WARN] {field['name']} ({field['filed_code']}) - 未关联任何模板") else: fields_with_relations.append({ 'field': field, 'templates': templates }) print(f" [OK] {field['name']} ({field['filed_code']}) - 关联了 {len(templates)} 个模板:") for template in templates: print(f" - {template['template_name']} (ID: {template['template_id']})") return { 'input_fields': input_fields, 'fields_without_relations': fields_without_relations, 'fields_with_relations': fields_with_relations } def check_output_field_relations_detail(conn) -> Dict: """详细检查输出字段的关联情况""" cursor = conn.cursor(pymysql.cursors.DictCursor) print("\n" + "="*80) print("3. 详细检查输出字段的关联情况") print("="*80) # 获取所有启用的输出字段 cursor.execute(""" SELECT id, name, filed_code FROM f_polic_field WHERE tenant_id = %s AND field_type = 2 AND state = 1 ORDER BY name """, (TENANT_ID,)) output_fields = cursor.fetchall() # 获取每个输出字段关联的模板 cursor.execute(""" SELECT f.id AS field_id, f.name AS field_name, f.filed_code AS field_code, fc.id AS template_id, fc.name AS template_name FROM f_polic_field f INNER JOIN f_polic_file_field fff ON f.id = fff.filed_id AND f.tenant_id = fff.tenant_id INNER JOIN f_polic_file_config fc ON fff.file_id = fc.id AND fff.tenant_id = fc.tenant_id WHERE f.tenant_id = %s AND f.field_type = 2 AND f.state = 1 AND fff.state = 1 AND fc.state = 1 ORDER BY f.name, fc.name """, (TENANT_ID,)) output_field_relations = cursor.fetchall() # 按字段分组 field_template_map = defaultdict(list) for rel in output_field_relations: field_template_map[rel['field_id']].append({ 'template_id': rel['template_id'], 'template_name': rel['template_name'] }) print(f"\n共找到 {len(output_fields)} 个启用的输出字段\n") fields_without_relations = [] fields_with_relations = [] for field in output_fields: field_id = field['id'] templates = field_template_map.get(field_id, []) if not templates: fields_without_relations.append(field) print(f" [WARN] {field['name']} ({field['filed_code']}) - 未关联任何模板") else: fields_with_relations.append({ 'field': field, 'templates': templates }) if len(templates) <= 5: print(f" [OK] {field['name']} ({field['filed_code']}) - 关联了 {len(templates)} 个模板:") for template in templates: print(f" - {template['template_name']} (ID: {template['template_id']})") else: print(f" [OK] {field['name']} ({field['filed_code']}) - 关联了 {len(templates)} 个模板") for template in templates[:3]: print(f" - {template['template_name']} (ID: {template['template_id']})") print(f" ... 还有 {len(templates) - 3} 个模板") return { 'output_fields': output_fields, 'fields_without_relations': fields_without_relations, 'fields_with_relations': fields_with_relations } def check_invalid_relations(conn) -> Dict: """检查无效的关联关系""" cursor = conn.cursor(pymysql.cursors.DictCursor) print("\n" + "="*80) print("4. 检查无效的关联关系") print("="*80) # 检查关联到不存在的 file_id cursor.execute(""" SELECT fff.id, fff.file_id, fff.filed_id, fff.tenant_id FROM f_polic_file_field fff LEFT JOIN f_polic_file_config fc ON fff.file_id = fc.id AND fff.tenant_id = fc.tenant_id WHERE fff.tenant_id = %s AND fc.id IS NULL """, (TENANT_ID,)) invalid_file_relations = cursor.fetchall() # 检查关联到不存在的 filed_id cursor.execute(""" SELECT fff.id, fff.file_id, fff.filed_id, fff.tenant_id FROM f_polic_file_field fff LEFT JOIN f_polic_field f ON fff.filed_id = f.id AND fff.tenant_id = f.tenant_id WHERE fff.tenant_id = %s AND f.id IS NULL """, (TENANT_ID,)) invalid_field_relations = cursor.fetchall() print(f"\n关联到不存在的 file_id: {len(invalid_file_relations)} 条") if invalid_file_relations: print(" 详情:") for rel in invalid_file_relations[:10]: print(f" - 关联ID: {rel['id']}, file_id: {rel['file_id']}, filed_id: {rel['filed_id']}") if len(invalid_file_relations) > 10: print(f" ... 还有 {len(invalid_file_relations) - 10} 条") else: print(" [OK] 没有无效的 file_id 关联") print(f"\n关联到不存在的 filed_id: {len(invalid_field_relations)} 条") if invalid_field_relations: print(" 详情:") for rel in invalid_field_relations[:10]: print(f" - 关联ID: {rel['id']}, file_id: {rel['file_id']}, filed_id: {rel['filed_id']}") if len(invalid_field_relations) > 10: print(f" ... 还有 {len(invalid_field_relations) - 10} 条") else: print(" [OK] 没有无效的 filed_id 关联") return { 'invalid_file_relations': invalid_file_relations, 'invalid_field_relations': invalid_field_relations } def get_summary_statistics(conn) -> Dict: """获取汇总统计信息""" cursor = conn.cursor(pymysql.cursors.DictCursor) print("\n" + "="*80) print("5. 汇总统计信息") print("="*80) # 总关联数 cursor.execute(""" SELECT COUNT(*) as total FROM f_polic_file_field WHERE tenant_id = %s AND state = 1 """, (TENANT_ID,)) total_relations = cursor.fetchone()['total'] # 输入字段关联数 cursor.execute(""" SELECT COUNT(*) as total FROM f_polic_file_field fff INNER JOIN f_polic_field f ON fff.filed_id = f.id AND fff.tenant_id = f.tenant_id WHERE fff.tenant_id = %s AND fff.state = 1 AND f.state = 1 AND f.field_type = 1 """, (TENANT_ID,)) input_relations = cursor.fetchone()['total'] # 输出字段关联数 cursor.execute(""" SELECT COUNT(*) as total FROM f_polic_file_field fff INNER JOIN f_polic_field f ON fff.filed_id = f.id AND fff.tenant_id = f.tenant_id WHERE fff.tenant_id = %s AND fff.state = 1 AND f.state = 1 AND f.field_type = 2 """, (TENANT_ID,)) output_relations = cursor.fetchone()['total'] # 关联的模板数 cursor.execute(""" SELECT COUNT(DISTINCT file_id) as total FROM f_polic_file_field WHERE tenant_id = %s AND state = 1 """, (TENANT_ID,)) related_templates = cursor.fetchone()['total'] # 关联的输入字段数 cursor.execute(""" SELECT COUNT(DISTINCT fff.filed_id) as total FROM f_polic_file_field fff INNER JOIN f_polic_field f ON fff.filed_id = f.id AND fff.tenant_id = f.tenant_id WHERE fff.tenant_id = %s AND fff.state = 1 AND f.state = 1 AND f.field_type = 1 """, (TENANT_ID,)) related_input_fields = cursor.fetchone()['total'] # 关联的输出字段数 cursor.execute(""" SELECT COUNT(DISTINCT fff.filed_id) as total FROM f_polic_file_field fff INNER JOIN f_polic_field f ON fff.filed_id = f.id AND fff.tenant_id = f.tenant_id WHERE fff.tenant_id = %s AND fff.state = 1 AND f.state = 1 AND f.field_type = 2 """, (TENANT_ID,)) related_output_fields = cursor.fetchone()['total'] print(f"\n总关联数: {total_relations}") print(f" 输入字段关联数: {input_relations}") print(f" 输出字段关联数: {output_relations}") print(f"\n关联的模板数: {related_templates}") print(f"关联的输入字段数: {related_input_fields}") print(f"关联的输出字段数: {related_output_fields}") return { 'total_relations': total_relations, 'input_relations': input_relations, 'output_relations': output_relations, 'related_templates': related_templates, 'related_input_fields': related_input_fields, 'related_output_fields': related_output_fields } def main(): """主函数""" print("="*80) print("全面检查 f_polic_file_field 表的关联关系") print("="*80) try: conn = pymysql.connect(**DB_CONFIG) print("[OK] 数据库连接成功\n") except Exception as e: print(f"[ERROR] 数据库连接失败: {e}") return try: # 1. 检查所有模板的字段关联情况 template_result = check_all_templates_field_relations(conn) # 2. 详细检查输入字段的关联情况 input_result = check_input_field_relations_detail(conn) # 3. 详细检查输出字段的关联情况 output_result = check_output_field_relations_detail(conn) # 4. 检查无效的关联关系 invalid_result = check_invalid_relations(conn) # 5. 获取汇总统计信息 stats = get_summary_statistics(conn) # 总结 print("\n" + "="*80) print("检查总结") print("="*80) issues = [] if len(template_result['templates_without_input']) > 0: issues.append(f"[WARN] {len(template_result['templates_without_input'])} 个模板缺少输入字段关联") if len(template_result['templates_without_output']) > 0: issues.append(f"[WARN] {len(template_result['templates_without_output'])} 个模板缺少输出字段关联") if len(template_result['templates_without_any']) > 0: issues.append(f"[WARN] {len(template_result['templates_without_any'])} 个模板没有任何字段关联") if len(input_result['fields_without_relations']) > 0: issues.append(f"[WARN] {len(input_result['fields_without_relations'])} 个输入字段未关联任何模板") if len(output_result['fields_without_relations']) > 0: issues.append(f"[WARN] {len(output_result['fields_without_relations'])} 个输出字段未关联任何模板") if len(invalid_result['invalid_file_relations']) > 0: issues.append(f"[ERROR] {len(invalid_result['invalid_file_relations'])} 条无效的 file_id 关联") if len(invalid_result['invalid_field_relations']) > 0: issues.append(f"[ERROR] {len(invalid_result['invalid_field_relations'])} 条无效的 filed_id 关联") if issues: print("\n发现以下问题:\n") for issue in issues: print(f" {issue}") else: print("\n[OK] 未发现明显问题") print("\n" + "="*80) except Exception as e: print(f"\n[ERROR] 检查过程中发生错误: {e}") import traceback traceback.print_exc() finally: conn.close() print("\n数据库连接已关闭") if __name__ == '__main__': main()