[英]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
有兩列: id
和history
。 history
是一條記錄, history.all_of_history
是一個重復的記錄,具有三個字段( is_active
、 start_date
和end_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 的高級概述:
您需要首先定義表的行類型,即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"));
}
};
rowType
,您需要在schemPlus
填充它。 讓我們將上面創建的表添加到方解石測試套件中存在的模式scott
中。 rootSchema.getParentSchema().getSubSchema("scott")).add("my_table", tableImpl)
schemaPlus
,您首先需要創建my_table
表掃描builder.scan("table_impl");
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();
unnestRel
變成一個標unnestRel
查詢: RelNode finalRel = builder.project(builder.field("id"), builder.scalarQuery(b -> unnestRel))
.build();
如果您覺得這有用,請點贊 :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.