فهرست منبع

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

wangxq 11 ماه پیش
والد
کامیت
8812a3b214
2فایلهای تغییر یافته به همراه448 افزوده شده و 135 حذف شده
  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