Browse Source

The ddl api is written and ready to be modified for the ddl save api.

wangxq 1 month ago
parent
commit
8812a3b214
2 changed files with 448 additions and 135 deletions
  1. 140 32
      app/api/data_resource/routes.py
  2. 308 103
      app/core/data_resource/resource.py

+ 140 - 32
app/api/data_resource/routes.py

@@ -32,6 +32,7 @@ from app.core.meta_data import (
     get_file_content,
     get_formatted_time
 )
+import traceback
 
 logger = logging.getLogger("app")
 
@@ -153,10 +154,12 @@ def data_resource_translate():
 
 @bp.route('/save', methods=['POST'])
 def data_resource_save():
-    """保存数据资源"""
+    """保存数据资源"""   
     try:
         # 获取表单数据
-        receiver = request.json.get('receiver', {})
+        # 表单以 receiver 开头时使用下面的方法:
+        # receiver = request.json.get('receiver', {})
+        receiver = request.get_json()
         additional_info = receiver['additional_info']
 
         # 检查receiver是否存在
@@ -236,6 +239,9 @@ def id_data_ddl():
         if not sql_content:
             return jsonify(failed("SQL内容不能为空"))
         
+        # 记录原始SQL用于调试
+        logger.debug(f"原始SQL: {sql_content}")
+        
         # 提取创建表的DDL语句
         create_ddl_list = select_create_ddl(sql_content)
         
@@ -243,44 +249,27 @@ def id_data_ddl():
             return jsonify(failed("未找到有效的CREATE TABLE语句"))
         
         # 解析每个表定义
-        tables = []
+        tables_dict = {}  # 最终返回的表字典
+        
         for ddl in create_ddl_list:
             table_info = table_sql(ddl)
             if table_info:
-                tables.append(table_info)
+                # table_info格式: {"table_name": {"exist": bool, "meta": [...], "table_comment": "..."}}
+                # 合并到结果字典中
+                tables_dict.update(table_info)
         
-        if not tables:
+        if not tables_dict:
             return jsonify(failed("解析表结构失败"))
         
-        # 转换结果为前端需要的格式
-        result = []
-        for table in tables:
-            table_result = {
-                "name": table["table_name"],
-                "en_name": table["table_name"],  # 初始使用原名
-                "fields": []
-            }
-            
-            # 处理每个字段
-            for field in table["fields"]:
-                field_info = {
-                    "name": field["name"],
-                    "en_name": field["name"],  # 初始使用原名
-                    "type": field["type"],
-                    "is_primary": field["is_primary"],
-                    "nullable": not field.get("not_null", False)
-                }
-                
-                if "default" in field:
-                    field_info["default"] = field["default"]
-                    
-                table_result["fields"].append(field_info)
-                
-            result.append(table_result)
+        # 记录结果
+        logger.debug(f"解析结果: {json.dumps(tables_dict, ensure_ascii=False)}")
+        
+        # 直接返回解析结果
+        return jsonify(success(tables_dict))
         
-        return jsonify(success(result))
     except Exception as e:
         logger.error(f"解析DDL失败: {str(e)}")
+        logger.error(traceback.format_exc())  # 添加详细错误堆栈
         return jsonify(failed(str(e)))
 
 @bp.route('/list', methods=['POST'])
@@ -492,6 +481,7 @@ def sql_test():
         logger.error(f"测试SQL查询失败: {str(e)}")
         return jsonify(failed(str(e)))
 
+# 废弃的识别DDL语句方法,该API 与 ddl API 功能类似,但功能简化了
 @bp.route('/ddl/identify', methods=['POST'])
 def sql_ddl_identify():
     """识别DDL语句"""
@@ -555,4 +545,122 @@ def data_resource_detail():
         return jsonify(success(resource_data))
     except Exception as e:
         logger.error(f"获取数据资源详情失败: {str(e)}")
-        return jsonify(failed(str(e))) 
+        return jsonify(failed(str(e)))
+
+    """解析表定义SQL,支持带schema和不带schema两种格式"""
+    try:
+        # 支持以下格式:
+        # 1. CREATE TABLE tablename
+        # 2. CREATE TABLE "tablename"
+        # 3. CREATE TABLE schema.tablename
+        # 4. CREATE TABLE "schema"."tablename"
+        table_name_pattern = r'CREATE\s+TABLE\s+(?:(?:"([^"]+)"|([^"\s\.]+))\.)?(?:"([^"]+)"|([^"\s\(]+))'
+        table_name_match = re.search(table_name_pattern, sql, re.IGNORECASE)
+        
+        if not table_name_match:
+            return None
+            
+        # 获取表名,优先使用带引号的名称,如果没有则使用不带引号的
+        schema = table_name_match.group(1) or table_name_match.group(2)  # schema是可选的
+        table_name = table_name_match.group(3) or table_name_match.group(4)  # 实际表名
+        
+        # 提取字段定义
+        fields_pattern = r'CREATE\s+TABLE[^(]*\(\s*(.*?)\s*\)'
+        fields_match = re.search(fields_pattern, sql, re.DOTALL | re.IGNORECASE)
+        
+        if not fields_match:
+            return None
+            
+        fields_text = fields_match.group(1)
+        
+        # 分割字段定义
+        field_definitions = []
+        in_parenthesis = 0
+        current_field = ""
+        
+        for char in fields_text:
+            if char == '(':
+                in_parenthesis += 1
+                current_field += char
+            elif char == ')':
+                in_parenthesis -= 1
+                current_field += char
+            elif char == ',' and in_parenthesis == 0:
+                field_definitions.append(current_field.strip())
+                current_field = ""
+            else:
+                current_field += char
+                
+        if current_field.strip():
+            field_definitions.append(current_field.strip())
+        
+        # 解析每个字段
+        fields = []
+        primary_keys = []
+        
+        for field_def in field_definitions:
+            # 忽略PRIMARY KEY等约束定义
+            if re.match(r'^\s*(?:PRIMARY|UNIQUE|FOREIGN|CHECK|CONSTRAINT)\s+', field_def, re.IGNORECASE):
+                # 提取主键字段
+                pk_pattern = r'PRIMARY\s+KEY\s*\(\s*(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))\s*\)'
+                pk_match = re.search(pk_pattern, field_def, re.IGNORECASE)
+                
+                if pk_match:
+                    pk = next((g for g in pk_match.groups() if g is not None), "")
+                    primary_keys.append(pk)
+                continue
+                
+            # 解析常规字段定义
+            field_pattern = r'^\s*(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))\s+([A-Za-z0-9_]+(?:\s*\([^)]*\))?)'
+            field_match = re.search(field_pattern, field_def)
+            
+            if field_match:
+                # 提取字段名和类型
+                field_name = next((g for g in field_match.groups()[:4] if g is not None), "")
+                field_type = field_match.group(5)
+                
+                # 检查是否为主键
+                is_primary = "PRIMARY KEY" in field_def.upper()
+                if is_primary:
+                    primary_keys.append(field_name)
+                
+                # 检查是否为非空
+                not_null = "NOT NULL" in field_def.upper()
+                
+                # 检查默认值
+                default_match = re.search(r'DEFAULT\s+([^,\s]+)', field_def, re.IGNORECASE)
+                default_value = default_match.group(1) if default_match else None
+                
+                # 添加字段信息
+                field_info = {
+                    "name": field_name,
+                    "type": clean_type(field_type),
+                    "is_primary": is_primary,
+                    "not_null": not_null
+                }
+                
+                if default_value:
+                    field_info["default"] = default_value
+                    
+                fields.append(field_info)
+        
+        # 更新主键标记
+        for field in fields:
+            if field["name"] in primary_keys and not field["is_primary"]:
+                field["is_primary"] = True
+        
+        # 返回结果,包含schema信息
+        result = {
+            "table_name": table_name,
+            "fields": fields
+        }
+        
+        # 如果有schema,添加到结果中
+        if schema:
+            result["schema"] = schema
+            
+        return result
+        
+    except Exception as e:
+        logger.error(f"解析表定义SQL失败: {str(e)}")
+        return None 

+ 308 - 103
app/core/data_resource/resource.py

@@ -532,7 +532,45 @@ def resource_impact_all_graph(resource_id, include_meta=True):
 
 def clean_type(type_str):
     """清洗SQL类型字符串"""
-    return re.sub(r'\(.*?\)', '', type_str).strip().upper()
+    # 提取基本类型,不包括长度或精度信息
+    basic_type = re.sub(r'\(.*?\)', '', type_str).strip().upper()
+    
+    # 移除 VARYING 这样的后缀
+    basic_type = re.sub(r'\s+VARYING$', '', basic_type)
+    
+    # 标准化常见类型
+    type_mapping = {
+        'INT': 'INTEGER',
+        'INT4': 'INTEGER',
+        'INT8': 'BIGINT',
+        'SMALLINT': 'SMALLINT',
+        'BIGINT': 'BIGINT',
+        'FLOAT4': 'FLOAT',
+        'FLOAT8': 'DOUBLE',
+        'REAL': 'FLOAT',
+        'DOUBLE PRECISION': 'DOUBLE',
+        'NUMERIC': 'DECIMAL',
+        'BOOL': 'BOOLEAN',
+        'CHARACTER': 'CHAR',
+        'CHAR VARYING': 'VARCHAR',
+        'CHARACTER VARYING': 'VARCHAR',
+        'TEXT': 'TEXT',
+        'DATE': 'DATE',
+        'TIME': 'TIME',
+        'TIMESTAMP': 'TIMESTAMP',
+        'TIMESTAMPTZ': 'TIMESTAMP WITH TIME ZONE',
+        'BYTEA': 'BINARY',
+        'JSON': 'JSON',
+        'JSONB': 'JSONB',
+        'UUID': 'UUID',
+        'SERIAL': 'SERIAL',
+        'SERIAL4': 'SERIAL',
+        'SERIAL8': 'BIGSERIAL',
+        'BIGSERIAL': 'BIGSERIAL'
+    }
+    
+    # 尝试从映射表中获取标准化的类型
+    return type_mapping.get(basic_type, basic_type)
 
 def clean_field_name(field_name):
     """清洗字段名"""
@@ -540,119 +578,293 @@ def clean_field_name(field_name):
 
 def select_create_ddl(sql_content):
     """从SQL内容中提取创建表的DDL语句"""
-    create_pattern = r'CREATE\s+TABLE.*?;'
-    matches = re.findall(create_pattern, sql_content, re.DOTALL | re.IGNORECASE)
-    return matches
+    try:
+        # 解析复杂的SQL文件,识别所有的CREATE TABLE语句及其关联的注释
+        # 找到所有以CREATE TABLE开头的语句块,每个语句块包含主语句和相关的注释
+        
+        # 首先,分割 SQL 内容按分号
+        statements = []
+        current_statement = ""
+        in_string = False
+        string_quote = None
+        
+        for char in sql_content:
+            if char in ["'", '"']:
+                if not in_string:
+                    in_string = True
+                    string_quote = char
+                elif char == string_quote:
+                    in_string = False
+                    string_quote = None
+                current_statement += char
+            elif char == ';' and not in_string:
+                current_statement += char
+                if current_statement.strip():
+                    statements.append(current_statement.strip())
+                current_statement = ""
+            else:
+                current_statement += char
+        
+        if current_statement.strip():
+            statements.append(current_statement.strip())
+        
+        # 找出所有的CREATE TABLE语句和关联的注释
+        create_table_statements = []
+        create_index = -1
+        in_table_block = False
+        current_table = None
+        current_block = ""
+        
+        for i, stmt in enumerate(statements):
+            if re.search(r'^\s*CREATE\s+TABLE', stmt, re.IGNORECASE):
+                # 如果已经在处理表,先保存当前块
+                if in_table_block and current_block:
+                    create_table_statements.append(current_block)
+                    
+                # 开始新的表块
+                in_table_block = True
+                current_block = stmt
+                
+                # 提取表名
+                table_match = re.search(r'CREATE\s+TABLE\s+(?:(?:"[^"]+"|\'[^\']+\'|[^"\'\s\.]+)\.)?(?:"([^"]+)"|\'([^\']+)\'|([^"\'\s\(]+))', stmt, re.IGNORECASE)
+                if table_match:
+                    current_table = table_match.group(1) or table_match.group(2) or table_match.group(3)
+                    current_table = current_table.strip('"\'') if current_table else ""
+            
+            elif in_table_block and (re.search(r'COMMENT\s+ON\s+TABLE', stmt, re.IGNORECASE) or 
+                                   re.search(r'COMMENT\s+ON\s+COLUMN', stmt, re.IGNORECASE)):
+                # 检查注释是否属于当前表
+                if current_table:
+                    # 表注释处理
+                    if re.search(r'COMMENT\s+ON\s+TABLE', stmt, re.IGNORECASE):
+                        table_comment_match = re.search(r'COMMENT\s+ON\s+TABLE\s+[\'"]?(\w+)[\'"]?', stmt, re.IGNORECASE)
+                        if table_comment_match:
+                            comment_table = table_comment_match.group(1).strip('"\'')
+                            if comment_table == current_table:
+                                current_block += " " + stmt
+                            else:
+                                # 这是另一个表的注释,当前表的DDL到此结束
+                                create_table_statements.append(current_block)
+                                in_table_block = False
+                                current_block = ""
+                                current_table = None
+                    # 列注释处理
+                    elif re.search(r'COMMENT\s+ON\s+COLUMN', stmt, re.IGNORECASE):
+                        column_comment_match = re.search(r'COMMENT\s+ON\s+COLUMN\s+[\'"]?(\w+)[\'"]?\.', stmt, re.IGNORECASE)
+                        if column_comment_match:
+                            comment_table = column_comment_match.group(1).strip('"\'')
+                            if comment_table == current_table:
+                                current_block += " " + stmt
+                            else:
+                                # 这是另一个表的注释,当前表的DDL到此结束
+                                create_table_statements.append(current_block)
+                                in_table_block = False
+                                current_block = ""
+                                current_table = None
+            
+            elif in_table_block and re.search(r'^\s*CREATE\s+', stmt, re.IGNORECASE):
+                # 如果遇到新的CREATE语句(不是注释),保存当前块并结束
+                create_table_statements.append(current_block)
+                in_table_block = False
+                current_block = ""
+                current_table = None
+        
+        # 添加最后一个块
+        if in_table_block and current_block:
+            create_table_statements.append(current_block)
+        
+        # 日志记录
+        logger.debug(f"提取到 {len(create_table_statements)} 个DDL语句")
+        for i, stmt in enumerate(create_table_statements):
+            logger.debug(f"DDL语句 {i+1}: {stmt}")
+            
+        return create_table_statements
+        
+    except Exception as e:
+        logger.error(f"提取DDL语句失败: {str(e)}")
+        logger.error(traceback.format_exc())
+        return []
 
 def table_sql(sql):
-    """解析表定义SQL"""
+    """解析表定义SQL,支持带schema和不带schema两种格式"""
     try:
-        # 提取表名
-        table_name_pattern = r'CREATE\s+TABLE\s+(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))'
-        table_name_match = re.search(table_name_pattern, sql, re.IGNORECASE)
+        # 支持以下格式:
+        # 1. CREATE TABLE tablename
+        # 2. CREATE TABLE "tablename"
+        # 3. CREATE TABLE 'tablename'
+        # 4. CREATE TABLE schema.tablename
+        # 5. CREATE TABLE "schema"."tablename"
+        # 6. CREATE TABLE 'schema'.'tablename'
+        # 匹配表名,支持带引号和不带引号的情况
+        table_pattern = r'CREATE\s+TABLE\s+(?:(?:"([^"]+)"|\'([^\']+)\'|([^"\'\s\.]+))\.)?(?:"([^"]+)"|\'([^\']+)\'|([^"\'\s\(]+))'
+        table_match = re.search(table_pattern, sql, re.IGNORECASE)
         
-        if not table_name_match:
+        if not table_match:
+            logger.error(f"无法匹配CREATE TABLE语句: {sql[:100]}...")
             return None
             
-        # 获取匹配的表名(从四个捕获组中选择非None的一个)
-        table_name = next((g for g in table_name_match.groups() if g is not None), "")
+        # 获取表名
+        schema = table_match.group(1) or table_match.group(2) or table_match.group(3)
+        table_name = table_match.group(4) or table_match.group(5) or table_match.group(6)
+        if not table_name:
+            logger.error("无法解析表名")
+            return None
+            
+        logger.debug(f"解析到表名: {table_name}")
         
-        # 提取字段定义
-        fields_pattern = r'CREATE\s+TABLE[^(]*\(\s*(.*?)\s*\)'
-        fields_match = re.search(fields_pattern, sql, re.DOTALL | re.IGNORECASE)
+        # 提取CREATE TABLE语句的主体部分(括号内的内容)
+        body_pattern = r'CREATE\s+TABLE\s+[^(]*\((.*?)\)(?=\s*;|\s*$)'
+        body_match = re.search(body_pattern, sql, re.DOTALL | re.IGNORECASE)
         
-        if not fields_match:
+        if not body_match:
+            logger.error("无法提取表主体内容")
             return None
             
-        fields_text = fields_match.group(1)
+        body_text = body_match.group(1).strip()
+        logger.debug(f"表定义主体部分: {body_text}")
         
-        # 分割字段定义
-        field_definitions = []
-        
-        # 处理字段定义,避免在逗号内的括号中分割
-        in_parenthesis = 0
-        current_field = ""
+        # 解析字段定义
+        fields = []
+        # 分割字段定义,处理括号嵌套和引号
+        field_defs = []
+        pos = 0
+        in_parentheses = 0
+        in_quotes = False
+        quote_char = None
         
-        for char in fields_text:
-            if char == '(':
-                in_parenthesis += 1
-                current_field += char
-            elif char == ')':
-                in_parenthesis -= 1
-                current_field += char
-            elif char == ',' and in_parenthesis == 0:
-                field_definitions.append(current_field.strip())
-                current_field = ""
-            else:
-                current_field += char
+        for i, char in enumerate(body_text):
+            if char in ["'", '"', '`'] and (not in_quotes or char == quote_char):
+                in_quotes = not in_quotes
+                if in_quotes:
+                    quote_char = char
+                else:
+                    quote_char = None
+            elif char == '(' and not in_quotes:
+                in_parentheses += 1
+            elif char == ')' and not in_quotes:
+                in_parentheses -= 1
+            elif char == ',' and in_parentheses == 0 and not in_quotes:
+                field_defs.append(body_text[pos:i].strip())
+                pos = i + 1
                 
-        if current_field.strip():
-            field_definitions.append(current_field.strip())
-        
-        # 解析每个字段
-        fields = []
-        primary_keys = []
+        # 添加最后一个字段定义
+        if pos < len(body_text):
+            field_defs.append(body_text[pos:].strip())
+            
+        logger.debug(f"解析出 {len(field_defs)} 个字段定义")
         
-        for field_def in field_definitions:
-            # 忽略PRIMARY KEY等约束定义
+        # 处理每个字段定义
+        for field_def in field_defs:
+            # 跳过约束定义
             if re.match(r'^\s*(?:PRIMARY|UNIQUE|FOREIGN|CHECK|CONSTRAINT)\s+', field_def, re.IGNORECASE):
-                # 提取主键字段
-                pk_pattern = r'PRIMARY\s+KEY\s*\(\s*(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))\s*\)'
-                pk_match = re.search(pk_pattern, field_def, re.IGNORECASE)
-                
-                if pk_match:
-                    pk = next((g for g in pk_match.groups() if g is not None), "")
-                    primary_keys.append(pk)
                 continue
                 
-            # 解析常规字段定义
-            field_pattern = r'^\s*(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))\s+([A-Za-z0-9_]+(?:\s*\([^)]*\))?)'
-            field_match = re.search(field_pattern, field_def)
+            # 提取字段名和类型
+            field_pattern = r'^\s*(?:"([^"]+)"|\'([^\']+)\'|`([^`]+)`|([a-zA-Z0-9_]+))\s+(.+?)(?:\s+DEFAULT\s+|\s+NOT\s+NULL|\s+REFERENCES|\s*$)'
+            field_match = re.search(field_pattern, field_def, re.IGNORECASE)
             
             if field_match:
-                # 提取字段名和类型
-                field_name = next((g for g in field_match.groups()[:4] if g is not None), "")
-                field_type = field_match.group(5)
-                
-                # 检查是否为主键
-                is_primary = "PRIMARY KEY" in field_def.upper()
-                if is_primary:
-                    primary_keys.append(field_name)
-                
-                # 检查是否为非空
-                not_null = "NOT NULL" in field_def.upper()
-                
-                # 检查默认值
-                default_match = re.search(r'DEFAULT\s+([^,\s]+)', field_def, re.IGNORECASE)
-                default_value = default_match.group(1) if default_match else None
-                
-                # 添加字段信息
-                field_info = {
-                    "name": field_name,
-                    "type": clean_type(field_type),
-                    "is_primary": is_primary,
-                    "not_null": not_null
-                }
+                # 提取字段名
+                field_name = field_match.group(1) or field_match.group(2) or field_match.group(3) or field_match.group(4)
+                # 提取类型
+                field_type = field_match.group(5).strip()
                 
-                if default_value:
-                    field_info["default"] = default_value
-                    
-                fields.append(field_info)
+                # 处理类型中可能的括号
+                type_base = re.split(r'\s+', field_type)[0]
+                clean_type_value = clean_type(type_base)
+                
+                fields.append((field_name, clean_type_value))
+                logger.debug(f"解析到字段: {field_name}, 类型: {clean_type_value}")
+            else:
+                logger.warning(f"无法解析字段定义: {field_def}")
         
-        # 更新主键标记
-        for field in fields:
-            if field["name"] in primary_keys and not field["is_primary"]:
-                field["is_primary"] = True
+        # 提取表注释
+        table_comment = ""
+        table_comment_pattern = r"COMMENT\s+ON\s+TABLE\s+(?:['\"]?(\w+)['\"]?)\s+IS\s+'([^']+)'"
+        table_comment_match = re.search(table_comment_pattern, sql, re.IGNORECASE)
+        
+        if table_comment_match:
+            comment_table = table_comment_match.group(1)
+            if comment_table.strip("'\"") == table_name.strip("'\""):
+                table_comment = table_comment_match.group(2)
+                logger.debug(f"找到表注释: {table_comment}")
+            
+        # 提取列注释
+        comments = {}
+        column_comment_pattern = r"COMMENT\s+ON\s+COLUMN\s+['\"]?(\w+)['\"]?\.['\"]?(\w+)['\"]?\s+IS\s+'([^']+)'"
+        
+        for match in re.finditer(column_comment_pattern, sql, re.IGNORECASE):
+            comment_table = match.group(1)
+            column_name = match.group(2)
+            comment = match.group(3)
+            
+            # 检查表名是否匹配
+            if comment_table.strip("'\"") == table_name.strip("'\""):
+                comments[column_name] = comment
+                logger.debug(f"找到列注释: {column_name} - {comment}")
+            else:
+                logger.debug(f"忽略列注释,表名不匹配: {comment_table} vs {table_name}")
         
-        # 返回结果
-        return {
-            "table_name": table_name,
-            "fields": fields
+        # 检查字段和注释匹配情况
+        logger.debug("========字段和注释匹配情况========")
+        field_names = [f[0] for f in fields]
+        logger.debug(f"字段列表 ({len(field_names)}): {field_names}")
+        logger.debug(f"注释字段 ({len(comments)}): {list(comments.keys())}")
+        
+        # 构建返回结果
+        meta_list = []
+        for field_name, field_type in fields:
+            chinese_name = comments.get(field_name, "")
+            meta_list.append({
+                "en_name": field_name,
+                "data_type": field_type,
+                "name": chinese_name if chinese_name else field_name
+            })
+            
+        # 检查表是否存在
+        try:
+            status = status_query([table_name])
+        except Exception as e:
+            logger.error(f"检查表存在状态失败: {str(e)}")
+            status = [False]
+            
+        # 构建返回结果
+        result = {
+            table_name: {
+                "exist": status[0] if status else False,
+                "meta": meta_list
+            }
         }
+        
+        logger.debug(f"解析结果: {json.dumps(result, ensure_ascii=False)}")
+        return result
+        
     except Exception as e:
         logger.error(f"解析表定义SQL失败: {str(e)}")
+        logger.error(f"异常详情: {e}")
+        import traceback
+        logger.error(traceback.format_exc())
         return None
 
+# 判断英文表名是否在图谱中存在
+def status_query(key_list):
+    query = """
+    unwind $Key_list as name
+    OPTIONAL MATCH (n:data_model {en_name: name})
+    OPTIONAL MATCH (n:data_resource {en_name: name})
+    OPTIONAL MATCH (n:data_metric {en_name: name})
+    WITH name, CASE 
+        WHEN n IS NOT NULL THEN True
+        ELSE False
+    END AS exist
+    return collect(exist)AS exist
+    """
+    with neo4j_driver.get_session() as session:
+        result = session.run(query, Key_list=key_list)
+        data = result.value() # 获取单个值
+    return data
+
+
 def select_sql(sql_query):
     """解析SELECT查询语句"""
     try:
@@ -720,24 +932,17 @@ def select_sql(sql_query):
             from_clause = from_match.group(1).strip()
             
             # 分析FROM子句中的表
-            table_pattern = r'(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))(?:\s+(?:AS\s+)?(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+)))?'
-            table_matches = re.finditer(table_pattern, from_clause)
-            
-            for match in table_matches:
-                table_name = next((g for g in match.groups()[:4] if g is not None), "")
-                table_alias = next((g for g in match.groups()[4:] if g is not None), table_name)
-                
-                tables.append({
-                    "name": table_name,
-                    "alias": table_alias
-                })
+            table_pattern = r'(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))(?:\s+(?:AS\s+)?(?:`([^`]+)`|"([^"]+)"|\'([^\']+)\'|([a-zA-Z0-9_]+))?'
+            for match in re.finditer(table_pattern, from_clause):
+                table_name = match.group(1) or match.group(2) or match.group(3) or match.group(4)
+                if table_name:
+                    tables.append(table_name)
+        
+        return tables
         
-        return {
-            "fields": parsed_fields,
-            "tables": tables
-        }
     except Exception as e:
         logger.error(f"解析SELECT查询语句失败: {str(e)}")
+        logger.error(traceback.format_exc())
         return None
 
 def model_resource_list(page, page_size, name_filter=None):
@@ -835,4 +1040,4 @@ def data_resource_edit(data):
             return dict(updated_node["n"])
     except Exception as e:
         logger.error(f"编辑数据资源失败: {str(e)}")
-        raise 
+        raise