簡體   English   中英

為未嵌套的重復記錄生成關系代數

[英]Generating relational algebra for unnested repeated records

如何為看起來像這樣的 SQL stmt 生成關系代數?

SELECT
  id,
  (
  SELECT
    h.is_active
  FROM
    UNNEST(history.all_of_history) h
  WHERE
    start_date <= "2021-06-01" AND (end_date >= "2021-06-01" OR end_date IS NULL))
FROM
  `table`

table有兩列: idhistory history是一條記錄, history.all_of_history是一個重復的記錄,具有三個字段( is_activestart_dateend_date

假設您只對邏輯計划感興趣,您提到的查詢的關系代數如下:

LogicalProject(id=[$0], $f1=[$SCALAR_QUERY({
LogicalProject(is_active=[$0])
  LogicalFilter(condition=[AND(<=($1, 2021-06-01), >=($2, 2021-06-01))])
    LogicalTableFunctionScan(invocation=[UNNEST($1)], rowType=[RecordType(BOOLEAN is_active, DATE start_date, DATE end_date)])
})])
  LogicalTableScan(table=[[scott, my_table]])

以下是有關如何創建 RelNode 的高級概述:

  1. 您需要首先定義表的行類型,即my_table

    1.1 你的行應該是這樣的:

    RecordType(INTEGER id, RecordType:peek(BOOLEAN is_active, DATE start_date, DATE end_date) MULTISET history)

    1.2 需要觀察history 它需要遵守UNNEST sql 函數的定義。 只是為了解釋這篇文章,我考慮了MULTISET數據類型。

    1.3 讓我們假設你只對邏輯計划感興趣,那么你可以創建一個簡單的表可以如下:

    Table tableImpl = new AbstractTable() {
      @Override
      public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        RelDataType id = typeFactory.createSqlType(SqlTypeName.INTEGER);
        List<RelDataType> historyRecordDataTypes = Arrays.asList(
            typeFactory.createSqlType(SqlTypeName.BOOLEAN),
            typeFactory.createSqlType(SqlTypeName.DATE),
            typeFactory.createSqlType(SqlTypeName.DATE)
            );
        List<String> historyRecordFieldNames = Arrays.asList("is_active", "start_date", "end_date");
        RelDataType history = typeFactory.createStructType(StructKind.PEEK_FIELDS, historyRecordDataTypes, historyRecordFieldNames);
        return typeFactory.createStructType(Arrays.asList(id, typeFactory.createMultisetType(history, -1L)), Arrays.asList("id", "history"));
      }
    };
  1. 創建表並定義其rowType ,您需要在schemPlus填充它。 讓我們將上面創建的表添加到方解石測試套件中存在的模式scott中。
     rootSchema.getParentSchema().getSubSchema("scott")).add("my_table", tableImpl)
  2. 創建自定義表並將其填充到schemaPlus ,您首先需要創建my_table表掃描
    builder.scan("table_impl");
  3. 然后你需要創建unnest子查詢的rel。 RelBuilder#functionScan(...)您需要使用RelBuilder#functionScan(...) API。 根據帖子中提到的查詢, unnestRelNode將如下所示:
        builder.functionScan(SqlStdOperatorTable.UNNEST, 0, builder.field("history"));
        List<RexNode> innerQueryFilterPredicates = Arrays.asList(
            // start_date <= "2021-06-01"
            builder.call(
                SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
                builder.field("start_date"), builder.getRexBuilder().makeDateLiteral(new DateString("2021-06-01"))),
            // end_date >= "2021-06-01" OR end_date IS NULL
            builder.call(
                SqlStdOperatorTable.OR,
                // end_date >= "2021-06-01"
                builder.call(
                    SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
                    builder.field("end_date"), builder.getRexBuilder().makeDateLiteral(new DateString("2021-06-01"))
                ),
                // end_date IS NULL
                builder.call(
                    SqlStdOperatorTable.IS_NULL, builder.field("end_date")
                )
            )
    
        );
        RelNode unnestRel = builder.filter(builder.call(SqlStdOperatorTable.AND, innerQueryFilterPredicates))
               .project(builder.field("is_active"))
               .build();
  1. 最后,為了創建最終的 RelNode,您需要將unnestRel變成一個標unnestRel查詢:
    RelNode finalRel = builder.project(builder.field("id"), builder.scalarQuery(b -> unnestRel))
           .build();

如果您覺得這有用,請點贊 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM