我爱普洱茶 发表于 2024-11-23 02:43:35

SQL字段来源表的解析

测试例子:

SELECT e.NAME, d.DEPT_NAME,d.DEPT_ID,EMP_ID,100+EMP_ID+100 FROM EMP e JOIN DEPT d ON e.DEPT_ID = d.DEPT_ID WHERE e.EMP_ID IN (SELECT EMP_ID FROM EMP WHERE DEPT_ID = 10) 代码示例:

package com.test;
import org.apache.calcite.jdbc.CalciteConnection;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.metadata.RelColumnOrigin;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.schema.impl.AbstractTable;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.tools.FrameworkConfig;
import org.apache.calcite.tools.Frameworks;
import org.apache.calcite.tools.Planner;
import org.apache.calcite.tools.RelConversionException;
import org.apache.calcite.tools.ValidationException;
import org.apache.calcite.rel.RelRoot;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.metadata.RelMetadataQuery;

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Set;

public class SqlLineageExample {

    public static void main(String[] args) throws SQLException, ValidationException, RelConversionException, SqlParseException {
      // 创建 Calcite 连接
      Properties info = new Properties();
      info.setProperty("lex", "JAVA");
      CalciteConnection connection = (CalciteConnection) DriverManager.getConnection("jdbc:calcite:", info);

      SchemaPlus rootSchema = connection.getRootSchema();

      // 定义并添加自定义表到 schema
      rootSchema.add("EMP", new AbstractTable() {
            @Override
            public RelDataType getRowType(RelDataTypeFactory typeFactory) {
                return typeFactory.builder()
                        .add("EMP_ID", SqlTypeName.INTEGER)
                        .add("NAME", SqlTypeName.VARCHAR, 20)
                        .add("DEPT_ID", SqlTypeName.INTEGER)
                        .build();
            }
      });

      rootSchema.add("DEPT", new AbstractTable() {
            @Override
            public RelDataType getRowType(RelDataTypeFactory typeFactory) {
                return typeFactory.builder()
                        .add("DEPT_ID", SqlTypeName.INTEGER)
                        .add("DEPT_NAME", SqlTypeName.VARCHAR, 20)
                        .build();
            }
      });

      // 创建 FrameworkConfig
      FrameworkConfig config = Frameworks.newConfigBuilder()
                .defaultSchema(rootSchema)
                .build();

      // 创建 Planner
      Planner planner = Frameworks.getPlanner(config);

      // 复杂 SQL 查询
      String sql = "SELECT e.NAME, d.DEPT_NAME,d.DEPT_ID,EMP_ID,100+EMP_ID+100 FROM EMP e JOIN DEPT d ON e.DEPT_ID = d.DEPT_ID " +
                "WHERE e.EMP_ID IN (SELECT EMP_ID FROM EMP WHERE DEPT_ID = 10)";

      // 解析 SQL
      SqlNode parsedNode = planner.parse(sql);

      // 校验 SQL
      SqlNode validatedNode = planner.validate(parsedNode);

      // 转换为关系代数树
      RelRoot relRoot = planner.rel(validatedNode);
      RelNode relNode = relRoot.project();

      // 打印字段来源
      printFieldLineage(relNode);
    }

    private static void printFieldLineage(RelNode relNode) {
      RelMetadataQuery mq = relNode.getCluster().getMetadataQuery();
      for (RelDataTypeField field : relNode.getRowType().getFieldList()) {
            Set<RelColumnOrigin> origins = mq.getColumnOrigins(relNode, field.getIndex());
            if (origins != null) {
                for (RelColumnOrigin origin : origins) {
                  String fieldName = field.getName();
                  String tableName = origin.getOriginTable().getQualifiedName().get(0);
                  System.out.println("Field: " + fieldName + " comes from Table: " + tableName);
                }
            } else {
                System.out.println("Field: " + field.getName() + " origin unknown");
            }
      }
    }
} 结果输出:

打印结果如下:
Field: NAME comes from Table: EMP
Field: DEPT_NAME comes from Table: DEPT
Field: DEPT_ID comes from Table: DEPT
Field: EMP_ID comes from Table: EMP
Field: EXPR$4 comes from Table: EMP
 
依赖 JAR包

<dependencies>
    <dependency>
      <groupId>org.apache.calcite</groupId>
      <artifactId>calcite-core</artifactId>
      <version>1.34.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.36</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.36</version>
    </dependency>
</dependencies>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: SQL字段来源表的解析