提交 153f16ad 编写于 作者: A Aristoeu 提交者: wangzelin.wzl

add common table expression in MySQL (#314)

上级 5f209b30
......@@ -12013,6 +12013,16 @@ static struct ObStrErrorInit
ORACLE_ERRNO[-OB_ERR_ILL_NAME_STRING] = 21560;
ORACLE_STR_ERROR[-OB_ERR_ILL_NAME_STRING] = "ORA-21560: unexpected name string '%.*s'";
ORACLE_STR_USER_ERROR[-OB_ERR_ILL_NAME_STRING] = "ORA-21560: unexpected name string '%.*s'";
ERROR_NAME[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "OB_ERR_CTE_NEED_QUERY_BLOCKS";
ERROR_CAUSE[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Internal Error";
ERROR_SOLUTION[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Contact OceanBase Support";
MYSQL_ERRNO[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = -1;
SQLSTATE[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "HY000";
STR_ERROR[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones";
STR_USER_ERROR[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s";
ORACLE_ERRNO[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = 600;
ORACLE_STR_ERROR[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "ORA-00600: internal error code, arguments: -5933, Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones";
ORACLE_STR_USER_ERROR[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "ORA-00600: internal error code, arguments: -5933, Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s";
ERROR_NAME[-OB_ERR_INCORRECT_VALUE_FOR_FUNCTION] = "OB_ERR_INCORRECT_VALUE_FOR_FUNCTION";
ERROR_CAUSE[-OB_ERR_INCORRECT_VALUE_FOR_FUNCTION] = "Internal Error";
ERROR_SOLUTION[-OB_ERR_INCORRECT_VALUE_FOR_FUNCTION] = "Contact OceanBase Support";
......@@ -1320,6 +1320,7 @@ DEFINE_ERROR_EXT(OB_ERR_WINDOW_NAME_IS_NOT_DEFINE, -5929, -1, "HY000", "Window n
DEFINE_ORACLE_ERROR(OB_ERR_OPEN_CURSORS_EXCEEDED, -5930, -1, "HY000", "maximum open cursors exceeded", 1000, "maximum open cursors exceeded");
DEFINE_ORACLE_ERROR(OB_ERR_ARG_INVALID, -5931, -1, "HY000", "argument is null, invalid, or out of range", 21560, "argument %.*s is null, invalid, or out of range");
DEFINE_ORACLE_ERROR(OB_ERR_ILL_NAME_STRING, -5932, -1, "HY000", "unexpected name string", 21560, "unexpected name string '%.*s'");
DEFINE_ERROR_EXT(OB_ERR_CTE_NEED_QUERY_BLOCKS, -5933, -1, "HY000", "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones", "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s");
DEFINE_ERROR_EXT(OB_ERR_INCORRECT_VALUE_FOR_FUNCTION, -5936, ER_WRONG_VALUE_FOR_TYPE, "HY000", "Incorrect value for function", "Incorrect %.*s value: '%.*s' for function %.*s");
DEFINE_ERROR_EXT(OB_ERR_USER_EXCEED_RESOURCE, -5967, 1226, "42000", "User has exceeded the resource", "User '%.*s' has exceeded the '%s' resource (current value: %lu)");
......
......@@ -1026,6 +1026,7 @@ constexpr int OB_ERR_WINDOW_NAME_IS_NOT_DEFINE = -5929;
constexpr int OB_ERR_OPEN_CURSORS_EXCEEDED = -5930;
constexpr int OB_ERR_ARG_INVALID = -5931;
constexpr int OB_ERR_ILL_NAME_STRING = -5932;
constexpr int OB_ERR_CTE_NEED_QUERY_BLOCKS = -5933;
constexpr int OB_ERR_INCORRECT_VALUE_FOR_FUNCTION = -5936;
constexpr int OB_ERR_USER_EXCEED_RESOURCE = -5967;
constexpr int OB_TRANSACTION_SET_VIOLATION = -6001;
......@@ -2428,6 +2429,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219;
#define OB_ERR_OPEN_CURSORS_EXCEEDED__USER_ERROR_MSG "maximum open cursors exceeded"
#define OB_ERR_ARG_INVALID__USER_ERROR_MSG "argument is null, invalid, or out of range"
#define OB_ERR_ILL_NAME_STRING__USER_ERROR_MSG "unexpected name string"
#define OB_ERR_CTE_NEED_QUERY_BLOCKS__USER_ERROR_MSG "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s"
#define OB_ERR_INCORRECT_VALUE_FOR_FUNCTION__USER_ERROR_MSG "Incorrect %.*s value: '%.*s' for function %.*s"
#define OB_ERR_USER_EXCEED_RESOURCE__USER_ERROR_MSG "User '%.*s' has exceeded the '%s' resource (current value: %lu)"
#define OB_TRANSACTION_SET_VIOLATION__USER_ERROR_MSG "Transaction set changed during the execution"
......@@ -3848,6 +3850,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219;
#define OB_ERR_OPEN_CURSORS_EXCEEDED__ORA_USER_ERROR_MSG "ORA-01000: maximum open cursors exceeded"
#define OB_ERR_ARG_INVALID__ORA_USER_ERROR_MSG "ORA-21560: argument %.*s is null, invalid, or out of range"
#define OB_ERR_ILL_NAME_STRING__ORA_USER_ERROR_MSG "ORA-21560: unexpected name string '%.*s'"
#define OB_ERR_CTE_NEED_QUERY_BLOCKS__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5933, Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s"
#define OB_ERR_INCORRECT_VALUE_FOR_FUNCTION__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5936, Incorrect %.*s value: '%.*s' for function %.*s"
#define OB_ERR_USER_EXCEED_RESOURCE__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5967, User '%.*s' has exceeded the '%s' resource (current value: %lu)"
#define OB_TRANSACTION_SET_VIOLATION__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -6001, Transaction set changed during the execution"
......
......@@ -272,6 +272,7 @@ READ { REPUT_TOKEN_NEG_SIGN(READ); }
READ_WRITE { REPUT_TOKEN_NEG_SIGN(READ_WRITE); }
READS { REPUT_TOKEN_NEG_SIGN(READS); }
REAL { REPUT_TOKEN_NEG_SIGN(REAL); }
RECURSIVE { REPUT_TOKEN_NEG_SIGN(RECURSIVE); }
RELEASE { REPUT_TOKEN_NEG_SIGN(RELEASE); }
REFERENCES { REPUT_TOKEN_NEG_SIGN(REFERENCES); }
REGEXP { REPUT_TOKEN_NEG_SIGN(REGEXP); }
......
......@@ -331,6 +331,7 @@ END_P SET_VAR DELIMITER
%type <node> insert_vals_list insert_vals value_or_values
%type <node> select_with_parens select_no_parens select_clause select_into no_table_select_with_order_and_limit simple_select_with_order_and_limit select_with_parens_with_order_and_limit select_clause_set select_clause_set_left select_clause_set_right select_clause_set_with_order_and_limit
%type <node> simple_select no_table_select limit_clause select_expr_list
%type <node> with_select with_clause with_list common_table_expr opt_column_alias_name_list alias_name_list column_alias_name
%type <node> opt_where opt_hint_value opt_groupby opt_rollup opt_order_by order_by opt_having groupby_clause
%type <node> opt_limit_clause limit_expr opt_for_update opt_for_update_wait
%type <node> sort_list sort_key opt_asc_desc sort_list_for_group_by sort_key_for_group_by opt_asc_desc_for_group_by opt_column_id
......@@ -6645,6 +6646,10 @@ select_no_parens opt_when
{
$$ = $1;
}
| with_select
{
$$ = $1;
}
;
// for select_into
......@@ -6667,7 +6672,10 @@ select_no_parens into_clause
select_with_parens:
'(' select_no_parens ')' { $$ = $2; }
| '(' select_with_parens ')' { $$ = $2; }
;
| '(' with_select ')'
{
$$ = $2;
};
select_no_parens:
select_clause opt_for_update
......@@ -8880,6 +8888,135 @@ OUTER { $$ = NULL; }
| /* EMPTY */ { $$ = NULL; }
;
/*****************************************************************************
*
* with clause (common table expression) (Mysql CTE grammer implement)
*
*
*****************************************************************************/
with_select:
with_clause select_no_parens opt_when
{
$$ = $2;
$$->children_[PARSE_SELECT_WHEN] = $3;
if (NULL == $$->children_[PARSE_SELECT_FOR_UPD] && NULL != $3)
{
malloc_terminal_node($$->children_[PARSE_SELECT_FOR_UPD], result->malloc_pool_, T_INT);
$$->children_[PARSE_SELECT_FOR_UPD]->value_ = -1;
}
$$->children_[PARSE_SELECT_WITH] = $1;
}
| with_clause select_with_parens
{
$$ = $2;
$$->children_[PARSE_SELECT_WITH] = $1;
}
;
with_clause:
WITH with_list
{
ParseNode *with_list = NULL;
merge_nodes(with_list, result, T_WITH_CLAUSE_LIST, $2);
$$ = with_list;
$$->value_ = 0;
}
|
WITH RECURSIVE with_list
{
ParseNode *with_list = NULL;
merge_nodes(with_list, result, T_WITH_CLAUSE_LIST, $3);
$$ = with_list;
$$->value_ = 1;
}/*
|
WITH RECURSIVE common_table_expr
{
$$ = $3;
$$->value_ = 0;
}*/
;
with_list:
with_list ',' common_table_expr
{
malloc_non_terminal_node($$, result->malloc_pool_, T_LINK_NODE, 2, $1, $3);
}
|common_table_expr
{
$$ = $1;
}
;
common_table_expr:
relation_name opt_column_alias_name_list AS '(' select_no_parens ')'
{
malloc_non_terminal_node($$, result->malloc_pool_, T_WITH_CLAUSE_AS, 5, $1, $2, $5, NULL, NULL);
}
| relation_name opt_column_alias_name_list AS '(' with_select ')'
{
malloc_non_terminal_node($$, result->malloc_pool_, T_WITH_CLAUSE_AS, 5, $1, $2, $5, NULL, NULL);
}
| relation_name opt_column_alias_name_list AS '(' select_with_parens ')'
{
if ($5->children_[PARSE_SELECT_ORDER] != NULL && $5->children_[PARSE_SELECT_FETCH] == NULL) {
yyerror(NULL, result, "only order by clause can't occur subquery\n");
YYABORT_PARSE_SQL_ERROR;
} else {
malloc_non_terminal_node($$, result->malloc_pool_, T_WITH_CLAUSE_AS, 5, $1, $2, $5, NULL, NULL);
}
}
;
opt_column_alias_name_list:
'(' alias_name_list ')'
{
ParseNode *col_alias_list = NULL;
merge_nodes(col_alias_list, result, T_COLUMN_LIST, $2);
$$ = col_alias_list;
}
|/*EMPTY*/
{ $$ = NULL; }
;
alias_name_list:
column_alias_name
{
$$ = $1;
}
|alias_name_list ',' column_alias_name
{
malloc_non_terminal_node($$, result->malloc_pool_, T_LINK_NODE, 2, $1, $3);
}
;
column_alias_name:
column_name
{
$$ = $1;
}
;
/*
search_list:
search_key
{ $$ = $1; }
| search_list ',' search_key
{ malloc_non_terminal_node($$, result->malloc_pool_, T_LINK_NODE, 2, $1, $3); }
;
search_key:
column_name opt_asc_desc
{
malloc_non_terminal_node($$, result->malloc_pool_, T_SORT_KEY, 2, $1, $2);
}
;*/
/*****************************************************************************
*
* CREATE OUTLINE grammar
......@@ -13189,6 +13326,7 @@ ACCOUNT
| REBUILD
| RECOVER
| RECOVERY
| RECURSIVE
| RECYCLE
| RECYCLEBIN
| ROTATE
......
......@@ -98,6 +98,7 @@ int ObSelectResolver::do_resolve_set_query_in_cte(const ParseNode& parse_tree)
right_resolver.set_current_level(current_level_);
right_resolver.set_in_set_query(true);
right_resolver.set_parent_namespace_resolver(parent_namespace_resolver_);
right_resolver.set_resolver(&left_resolver);
OC((left_resolver.set_cte_ctx)(cte_ctx_));
OC((right_resolver.set_cte_ctx)(cte_ctx_));
......@@ -124,6 +125,7 @@ int ObSelectResolver::do_resolve_set_query_in_cte(const ParseNode& parse_tree)
LOG_WARN("failed to identify anchor member", K(ret));
} else if (!need_swap_child) {
left_select_stmt = identify_anchor_resolver.get_child_stmt();
right_resolver.set_resolver(&identify_anchor_resolver);
} else {
left_member = PARSE_SELECT_LATER;
right_member = PARSE_SELECT_FORMER;
......@@ -136,6 +138,26 @@ int ObSelectResolver::do_resolve_set_query_in_cte(const ParseNode& parse_tree)
}
}
if (OB_SUCC(ret)) {
if (!params_.has_cte_param_list_ && right_resolver.saved_left_resolver != NULL &&
!right_resolver.saved_left_resolver->cte_ctx_.cte_col_names_.empty()) {
right_resolver.cte_ctx_.cte_col_names_.reset();
cte_ctx_.cte_col_names_.reset();
for (int64_t i = 0; OB_SUCC(ret) && i < right_resolver.saved_left_resolver->cte_ctx_.cte_col_names_.count(); ++i) {
if (OB_FAIL(right_resolver.cte_ctx_.cte_col_names_.push_back(
right_resolver.saved_left_resolver->cte_ctx_.cte_col_names_.at(i)))) { // to right resolver
ret = OB_ERR_UNEXPECTED;
LOG_WARN("pass cte column name to child resolver failed");
}
if (OB_FAIL(cte_ctx_.cte_col_names_.push_back(
right_resolver.saved_left_resolver->cte_ctx_.cte_col_names_.at(i)))) { // to parent resolver
ret = OB_ERR_UNEXPECTED;
LOG_WARN("pass cte column name to child resolver failed");
}
}
}
}
if (OB_FAIL(ret)) {
} else if (OB_FALSE_IT(right_resolver.cte_ctx_.set_recursive_right_branch(
left_select_stmt, parse_tree.children_[left_member], !select_stmt->is_set_distinct()))) {
......@@ -449,6 +471,7 @@ int ObSelectResolver::set_cte_ctx(ObCteResolverCtx& cte_ctx, bool copy_col_name
{
int ret = OB_SUCCESS;
cte_ctx_ = cte_ctx;
cte_ctx_.is_recursive_cte_ = false;
cte_ctx_.cte_col_names_.reset();
cte_ctx_.is_cte_subquery_ = in_subquery;
if (cte_ctx_.is_with_resolver())
......@@ -1517,6 +1540,13 @@ int ObSelectResolver::resolve_field_list(const ParseNode& node)
} else { /*do nothing*/
}
// add for cte:
if (OB_SUCC(ret) && !params_.has_cte_param_list_) {
if (OB_FAIL(cte_ctx_.cte_col_names_.push_back(select_item.alias_name_))) {
LOG_WARN("push back column alia name failed", K(ret));
}
}
} // end for
// for aggr exprs in having clause to remove duplicate;
......@@ -2130,12 +2160,12 @@ int ObSelectResolver::resolve_with_clause(const ParseNode* node, bool same_level
ObSelectStmt* select_stmt = NULL;
TableItem* table_item = NULL;
bool duplicate_name = false;
if (NULL != node && cte_ctx_.is_with_resolver() && same_level == false){
LOG_DEBUG("same_level = false, oracle not supported, mysql feature");
}
if (OB_ISNULL(select_stmt = get_select_stmt())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(select_stmt), K_(node->type));
} else if (NULL != node && cte_ctx_.is_with_resolver() && same_level == false) {
ret = OB_ERR_UNSUPPORTED_USE_OF_CTE;
LOG_WARN("invalid argument, oracle cte do not support a with clause nest", K(select_stmt), K_(node->type));
} else if (OB_ISNULL(node)) {
// do nothing
} else if (OB_UNLIKELY(node->type_ != T_WITH_CLAUSE_LIST)) {
......@@ -2144,6 +2174,10 @@ int ObSelectResolver::resolve_with_clause(const ParseNode* node, bool same_level
LOG_WARN("resolver with_clause_as met unexpected node type", K_(node->type));
} else {
int num_child = node->num_child_;
if (node->value_ == 0)
params_.has_recursive_word = false;
else
params_.has_recursive_word = true;
for (int64_t i = 0; OB_SUCC(ret) && i < num_child; ++i) {
// alias tblname [(alia colname1, alia colname2)](subquery) [search clause][cycle clause]
ParseNode* child_node = node->children_[i];
......@@ -2981,7 +3015,7 @@ int ObSelectResolver::add_fake_schema(ObSelectStmt* left_stmt)
ObColumnRefRawExpr* select_expr = static_cast<ObColumnRefRawExpr*>(expr);
ObColumnSchemaV2* new_col = static_cast<ObColumnSchemaV2*>(allocator_->alloc(sizeof(ObColumnSchemaV2)));
new_col = new (new_col) ObColumnSchemaV2(allocator_);
new_col->set_column_name(cte_ctx_.cte_col_names_.at(i));
new_col->set_column_name(saved_left_resolver->cte_ctx_.cte_col_names_.at(i));
new_col->set_tenant_id(tbl_schema->get_tenant_id());
new_col->set_table_id(magic_table_id);
new_col->set_column_id(magic_col_id + i);
......@@ -3010,7 +3044,9 @@ int ObSelectResolver::get_opt_alias_colnames_for_recursive_cte(ObIArray<ObString
int ret = OB_SUCCESS;
if (OB_ISNULL(parse_tree)) {
LOG_DEBUG("the opt_alias_colnames parse tree is null");
params_.has_cte_param_list_ = false;
} else {
params_.has_cte_param_list_ = true;
int64_t alias_num = parse_tree->num_child_;
for (int64_t i = 0; OB_SUCC(ret) && i < alias_num; ++i) {
if (parse_tree->children_[i]->str_len_ <= 0) {
......@@ -5456,7 +5492,12 @@ int ObSelectResolver::identify_anchor_member(
if (OB_FAIL(identify_anchor_resolver.resolve_child_stmt(parse_tree))) {
if (OB_ERR_NEED_INIT_BRANCH_IN_RECURSIVE_CTE == ret) {
need_swap_childa = true;
ret = OB_SUCCESS;
if (is_oracle_mode()){
ret = OB_SUCCESS;
} else if (params_.has_recursive_word) {
ret = OB_ERR_CTE_NEED_QUERY_BLOCKS; // mysql error: Recursive Common Table Expression 'cte' should have one or
// more non-recursive query blocks followed by one or more recursive ones
}
} else {
LOG_WARN("Failed to find anchor member", K(ret));
}
......
......@@ -229,6 +229,9 @@ public:
}
// function members
TO_STRING_KV(K_(has_calc_found_rows), K_(has_top_limit), K_(in_set_query), K_(in_subquery));
void set_resolver(ObSelectResolver* resolver){
saved_left_resolver = resolver;
}
protected:
int resolve_set_query(const ParseNode& parse_node);
......@@ -432,6 +435,8 @@ protected:
bool in_subquery_;
// query is subquery in exists
bool in_exists_subquery_;
ObSelectResolver* saved_left_resolver = NULL;
// used to store left resolver and get alias name
ObStandardGroupChecker standard_group_checker_;
const TransposeItem* transpose_item_;
......
......@@ -287,6 +287,8 @@ struct ObResolverParams {
new_gen_wid_(1),
is_multi_table_insert_(false),
is_resolve_table_function_expr_(false),
has_cte_param_list_(false),
has_recursive_word(false),
is_column_ref_(true)
{}
bool is_force_trace_log()
......@@ -340,6 +342,8 @@ private:
public:
bool is_multi_table_insert_; // used to mark is multi table insert
bool is_resolve_table_function_expr_; // used to mark resolve table function expr.
bool has_cte_param_list_;
bool has_recursive_word;
bool is_column_ref_; // used to mark normal column ref
};
} // end namespace sql
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
with cte(a,b) as (select 1 from dual) select * from cte;
ERROR 5740 (HY000): number of WITH clause column names does not match number of elements in select list
with cte(a,b) as (with cte2(a,b) as (select 1,1 from dual) select a,b from cte) select * from cte;
ERROR 5742 (HY000): recursive WITH clause must use a UNION ALL operation
with cte(a,a) as (select 1 from dual) select * from cte;
ERROR 5751 (HY000): duplicate name found in column alias list for WITH clause
with cte as (select 1,1 from dual union all select a+1,b+1 from cte where cte.a < 10) select * from cte;
ERROR 1054 (42S22): Unknown column 'cte.a' in 'where clause'
# MySQL不支持search depth关键字
with cte(a,b,c) as
(
select 1,2,3 from dual
union all
select a+1,b+1,c+1 from cte where cte.c < 10
) search depth first by d set pcol select * from cte;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your OceanBase version for the right syntax to use near 'search depth first by d set pcol select * from cte' at line 6
# MySQL不支持cycle关键字
with cte(n, x) as (select /*+ materialize */ 1,2 from dual) cycle n,n set iscyc to 'aaaaay' default 'n' select * from cte;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your OceanBase version for the right syntax to use near 'cycle n,n set iscyc to 'aaaaay' default 'n' select * from cte' at line 1
with cte(a,b,c) as
(
select 1,2,3 from dual
union
select a+1,b+1,c+1 from cte, cte b where cte.c < 10 and b.c = cte.c
) select * from cte;
ERROR 5742 (HY000): recursive WITH clause must use a UNION ALL operation
with cte(a,b,c) as
(
select 1,2,3 from dual
union all
select 1,2,3 from dual
union all
select a+1,b+1,c+1 from cte, cte b where cte.c < 10 and b.c = cte.c
) select * from cte;
ERROR 5762 (HY000): recursive query name referenced more than once in recursive branch of recursive WITH clause element
with t1 as (select c1 from t1) select * from t1;
ERROR 5741 (HY000): recursive WITH clause must have column alias list
## success
with cte1(a,b) as (select 'a','b' from dual), cte2 as (select * from cte1 where b > 'c'), cte3 as (select * from cte2 where a > 1 union select * from cte2 where a > 1) select * from cte3;
Empty set
with cte(a) as (select 1,1 from dual union all select a+1, a+1 from cte where a+1 < 10) select * from cte;
ERROR 5740 (HY000): number of WITH clause column names does not match number of elements in select list
with cte(n) AS (select 1 from dual UNION ALL select n+1 from cte where n < 3 UNION ALL select 2 from dual) select * from cte;
ERROR 5743 (HY000): UNION ALL operation in recursive WITH clause must have only two branches
with cte(n) AS ( select 1 from dual UNION ALL select sum(n+1) from cte) select * from cte;
ERROR 5758 (HY000): unsupported operation in recursive branch of recursive WITH clause
with cte(n) AS ( select 1 from dual UNION ALL select (select 1 from dual) from cte where cte.n < 2) select * from cte;
ERROR 5746 (HY000): cycle detected while executing recursive WITH query
with cte (c1, c2, c3) as ( select * from ( select c1, c2, c3 from t1 union select c1, c2, c3 from t1) where c1 = 1 union all select * from t1 join cte c on t1.c1 = c.c1 where c.c1 < 10 ) select * from cte;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
with cte(n) AS ( select 1 from cte) select * from cte;
ERROR 5742 (HY000): recursive WITH clause must use a UNION ALL operation
with cte(n) AS (select 1 from dual UNION ALL select n+1 from cte where n < 3 order by n ) select * from cte;
ERROR 1054 (42S22): Unknown column 'n' in 'order clause'
with cte1(c1, c2) as
(select 1, '0' from dual
union all select 2, '1' from dual
),
cte2(c1, c2) as
(select '0', 1 from dual
union all select cte1.c2, cte1.c1 from cte2, cte1 where 10 = cte2.c1)
select * from cte1;
+------+------+
| c1 | c2 |
+------+------+
| 1 | 0 |
| 2 | 1 |
+------+------+
\ No newline at end of file
drop database if exists ctetest;
create database ctetest;
use ctetest;
create table EMP (
EMPno number,
ENAME varchar(30),
JOB varchar(30),
MGR number(4),
HIREDATE date,
SAL number(7,2),
COMM number(7,2),
DEPTNO number(2)
) ;
create table DEPT(
DEPTNO number(2),
DNAME char(45),
LOC varchar(39)
) ;
insert into EMP values (7369,'SMITH','CLERK',7902, str_to_date('17-DEC-80','%d-%b-%Y'),800,NULL, 20) ;
INSERT INTO EMP VALUES (7499, 'ALLEN','SALESMAN',7698,str_to_date('20-FEB-81','%d-%b-%Y'),1600,300,30) ;
INSERT INTO EMP VALUES (7521,'WARD','SALESMAN',7698, str_to_date('22-FEB-81','%d-%b-%Y'),1250, 500, 30) ;
INSERT INTO EMP VALUES (7566,'JONES','MANAGER',7839, str_to_date('02-APR-81','%d-%b-%Y'), 2975, NULL, 20) ;
INSERT INTO EMP VALUES (7654,'MARTIN','SALESMAN', 7698, str_to_date('28-SEP-81','%d-%b-%Y'), 1250, 1400, 30) ;
INSERT INTO EMP VALUES (7698, 'BLAKE','MANAGER', 7839, str_to_date('01-MAY-81','%d-%b-%Y'), 2850, NULL, 30) ;
INSERT INTO EMP VALUES (7782, 'CLARK','MANAGER', 7839, str_to_date('09-JUN-81','%d-%b-%Y'), 2450, NULL, 10) ;
insert into EMP values (7788,'SCOTT','ANALYST', 7566, str_to_date('19-APR-87','%d-%b-%Y'), 3000, null, 20) ;
INSERT INTO EMP VALUES (7839, 'KING','PRESIDENT', NULL, str_to_date('17-NOV-81','%d-%b-%Y'), 5000, NULL, 10) ;
INSERT INTO EMP VALUES (7844, 'TURNER','SALESMAN', 7698, str_to_date('08-SEP-81','%d-%b-%Y'), 1500, 0, 30) ;
INSERT INTO EMP VALUES(7876, 'ADAMS','CLERK', 7788, str_to_date('23-MAY-87','%d-%b-%Y'), 1100, NULL, 20) ;
INSERT INTO EMP VALUES(7900, 'JAMES', 'CLEARK', 7698, str_to_date('03-DEC-81','%d-%b-%Y'), 950, NULL, 30) ;
INSERT INTO EMP VALUES(7902, 'FORD','ANALYST',7566, str_to_date('03-DEC-81','%d-%b-%Y'), 3000, NULL, 20) ;
INSERT INTO EMP VALUES(7934,'MILLER','CLERK', 7782, str_to_date('23-JAN-82','%d-%b-%Y'), 1300,NULL, 10) ;
result_format: 4
## =======================================================================
## Test Case 1:
## - recursive WITH Query: Optimization on query with outside filter.
## Predicate pushdown optimization on static value job.
## The plan should reflect optimization or development can provide
## parameter to show that pushdown optimization happened for init branch
## =======================================================================
explain basic
WITH rw (ename, mgr, empno, job) AS
(
SELECT ename, mgr, empno, job
FROM emp e
UNION ALL
SELECT e.ename, e.mgr, e.empno, e.job
FROM rw r, emp e
WHERE r.empno = e.mgr
)
SELECT ename, empno, mgr, job
FROM rw
WHERE job = 'PRESIDENT' ;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ==============================
|ID|OPERATOR |NAME|
------------------------------
|0 |SUBPLAN SCAN |rw |
|1 | RECURSIVE UNION ALL| |
|2 | TABLE SCAN |e |
|3 | HASH JOIN | |
|4 | TABLE SCAN |e |
|5 | TABLE SCAN |r |
==============================
Outputs & filters:
-------------------------------------
0 - output([rw.ename], [rw.empno], [rw.mgr], [rw.job]), filter([rw.job = 'PRESIDENT']),
access([rw.job], [rw.ename], [rw.empno], [rw.mgr])
1 - output([UNION([1])], [UNION([2])], [UNION([3])], [UNION([4])]), filter(nil)
2 - output([e.ENAME], [e.MGR], [e.EMPno], [e.JOB]), filter(nil),
access([e.ENAME], [e.MGR], [e.EMPno], [e.JOB]), partitions(p0)
3 - output([e.ENAME], [e.MGR], [e.EMPno], [e.JOB]), filter(nil),
equal_conds([r.empno = e.MGR]), other_conds(nil)
4 - output([e.MGR], [e.ENAME], [e.EMPno], [e.JOB]), filter(nil),
access([e.MGR], [e.ENAME], [e.EMPno], [e.JOB]), partitions(p0)
5 - output([r.empno]), filter(nil),
access([r.empno]), partitions(nil)
|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
WITH rw (ename, mgr, empno, job) AS
(
SELECT ename, mgr, empno, job
FROM emp e
UNION ALL
SELECT e.ename, e.mgr, e.empno, e.job
FROM rw r, emp e
WHERE r.empno = e.mgr
)
SELECT /*+ :HINT: */ ename, empno, mgr, job
FROM rw
WHERE job = 'PRESIDENT' ;
+-------+-------+------+-----------+
| ename | empno | mgr | job |
+-------+-------+------+-----------+
| KING | 7839 | NULL | PRESIDENT |
+-------+-------+------+-----------+
with cte(a,b) as (select 1 from dual) select * from cte;
with cte(a,b) as (with cte2(a,b) as (select 1,1 from dual) select a,b from cte) select * from cte;
with cte(a,a) as (select 1 from dual) select * from cte;
with cte as (select 1,1 from dual union all select a+1,b+1 from cte where cte.a < 10) select * from cte;
# MySQL不支持search depth关键字
with cte(a,b,c) as
(
select 1,2,3 from dual
union all
select a+1,b+1,c+1 from cte where cte.c < 10
) search depth first by d set pcol select * from cte;
# MySQL不支持cycle关键字
with cte(n, x) as (select /*+ materialize */ 1,2 from dual) cycle n,n set iscyc to 'aaaaay' default 'n' select * from cte;
with cte(a,b,c) as
(
select 1,2,3 from dual
union
select a+1,b+1,c+1 from cte, cte b where cte.c < 10 and b.c = cte.c
) select * from cte;
with cte(a,b,c) as
(
select 1,2,3 from dual
union all
select 1,2,3 from dual
union all
select a+1,b+1,c+1 from cte, cte b where cte.c < 10 and b.c = cte.c
) select * from cte;
with t1 as (select c1 from t1) select * from t1;
## success
with cte1(a,b) as (select 'a','b' from dual), cte2 as (select * from cte1 where b > 'c'), cte3 as (select * from cte2 where a > 1 union select * from cte2 where a > 1) select * from cte3;
with cte(a) as (select 1,1 from dual union all select a+1, a+1 from cte where a+1 < 10) select * from cte;
with cte(n) AS (select 1 from dual UNION ALL select n+1 from cte where n < 3 UNION ALL select 2 from dual) select * from cte;
with cte(n) AS ( select 1 from dual UNION ALL select sum(n+1) from cte) select * from cte;
with cte(n) AS ( select 1 from dual UNION ALL select (select 1 from dual) from cte where cte.n < 2) select * from cte;
with cte (c1, c2, c3) as ( select * from ( select c1, c2, c3 from t1 union select c1, c2, c3 from t1) where c1 = 1 union all select * from t1 join cte c on t1.c1 = c.c1 where c.c1 < 10 ) select * from cte;
with cte(n) AS ( select 1 from cte) select * from cte;
with cte(n) AS (select 1 from dual UNION ALL select n+1 from cte where n < 3 order by n ) select * from cte;
# cases in MySQL document: https://dev.mysql.com/doc/refman/8.0/en/with.html
WITH RECURSIVE cte (n) AS
(
SELECT 1
UNION ALL
SELECT n + 1 FROM cte WHERE n < 5
)
SELECT * FROM cte;
WITH RECURSIVE cte AS
(
SELECT 1 AS n, CAST('abc' AS CHAR(20)) AS str
UNION ALL
SELECT n + 1, CONCAT(str, str) FROM cte WHERE n < 3
)
SELECT * FROM cte;
WITH RECURSIVE cte AS
(
SELECT 1 AS n, 1 AS p, -1 AS q
UNION ALL
SELECT n + 1, q * 2, p * 2 FROM cte WHERE n < 5
)
SELECT * FROM cte;
WITH RECURSIVE fibonacci (n, fib_n, next_fib_n) AS
(
SELECT 1, 0, 1
UNION ALL
SELECT n + 1, next_fib_n, fib_n + next_fib_n
FROM fibonacci WHERE n < 10
)
SELECT * FROM fibonacci;
WITH RECURSIVE fibonacci (n, fib_n, next_fib_n) AS
(
SELECT 1, 0, 1
UNION ALL
SELECT n + 1, next_fib_n, fib_n + next_fib_n
FROM fibonacci WHERE n < 10
)
SELECT fib_n FROM fibonacci WHERE n = 8;
create table sales(date DATE,price NUMBER(7,2));
insert into sales values(str_to_date('2017-01-03', '%Y-%m-%d'),100);
insert into sales values(str_to_date('2017-01-03', '%Y-%m-%d'),200);
insert into sales values(str_to_date('2017-01-06', '%Y-%m-%d'),50);
insert into sales values(str_to_date('2017-01-08', '%Y-%m-%d'),10);
insert into sales values(str_to_date('2017-01-08', '%Y-%m-%d'),20);
insert into sales values(str_to_date('2017-01-08', '%Y-%m-%d'),150);
insert into sales values(str_to_date('2017-01-10', '%Y-%m-%d'),5);
SELECT * FROM sales ORDER BY date, price;
SELECT date, SUM(price) AS sum_price
FROM sales
GROUP BY date
ORDER BY date;
WITH RECURSIVE dates (date) AS
(
SELECT MIN(date) FROM sales
UNION ALL
SELECT date + INTERVAL 1 DAY FROM dates
WHERE date + INTERVAL 1 DAY <= (SELECT MAX(date) FROM sales)
)
SELECT * FROM dates;
WITH RECURSIVE dates (date) AS
(
SELECT MIN(date) FROM sales
UNION ALL
SELECT date + INTERVAL 1 DAY FROM dates
WHERE date + INTERVAL 1 DAY <= (SELECT MAX(date) FROM sales)
)
SELECT dates.date, COALESCE(SUM(price), 0) AS sum_price
FROM dates LEFT JOIN sales ON dates.date = sales.date
GROUP BY dates.date
ORDER BY dates.date;
################################################################################################
### PART 1 SQL syntax
################################################################################################
WITH cte1(txt) AS (SELECT "This "),
cte2(txt) AS (SELECT CONCAT(cte1.txt,"is a ") FROM cte1),
cte3(txt) AS (SELECT "nice query" UNION
SELECT "query that rocks" UNION
SELECT "query"),
cte4(txt) AS (SELECT concat(cte2.txt, cte3.txt) FROM cte2, cte3)
SELECT MAX(txt), MIN(txt) FROM cte4;
WITH RECURSIVE my_cte AS
(
SELECT 1 AS n
UNION ALL
SELECT 1+n FROM my_cte WHERE n<10
)
SELECT * FROM my_cte;
CREATE TABLE numbers
WITH RECURSIVE my_cte(n) AS
(
SELECT 1
UNION ALL
SELECT 1+n FROM my_cte WHERE n<6
)
SELECT * FROM my_cte;
SELECT * FROM numbers;
INSERT INTO numbers
WITH RECURSIVE my_cte(n) AS
(
SELECT 1
UNION ALL
SELECT 1+n FROM my_cte WHERE n<6
)
SELECT * FROM my_cte;
SELECT * FROM numbers;
DELETE FROM numbers
WHERE numbers.n >
(
WITH RECURSIVE my_cte(n) AS
(
SELECT 1
UNION ALL
SELECT 1+n FROM my_cte WHERE n<6
)
SELECT AVG(n)/2 FROM my_cte
);
SELECT * FROM numbers;
################################################################################################
### PART 2 generating series
################################################################################################
WITH RECURSIVE my_cte AS
(
SELECT 1 as f, 1 as next_f
UNION ALL
SELECT next_f, f+next_f FROM my_cte WHERE f < 500
)
SELECT * FROM my_cte;
WITH RECURSIVE
digits AS
(
SELECT '0' AS d UNION ALL SELECT '1'
),
strings AS
(
SELECT CAST('' AS CHAR(4)) AS s
UNION ALL
SELECT CONCAT(strings.s, digits.d)
FROM strings, digits
WHERE LENGTH(strings.s) < 4
)
SELECT * FROM strings WHERE LENGTH(s)=4;
################################################################################################
### PART 3 hierarchies
################################################################################################
CREATE TABLE category(
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
parent INT DEFAULT NULL
);
INSERT INTO category VALUES(1,'ELECTRONICS',NULL),(2,'TELEVISIONS',1),(3,'TUBE',2),
(4,'LCD',2),(5,'PLASMA',2),(6,'PORTABLE ELECTRONICS',1),(7,'MP3 PLAYERS',6),(8,'FLASH',7),
(9,'CD PLAYERS',6),(10,'2 WAY RADIOS',6);
SELECT * FROM category ORDER BY category_id;
#Retrieving a Full Tree
WITH RECURSIVE cte AS
(
# seed SELECT
SELECT category_id, name FROM category WHERE parent IS NULL
UNION ALL
# recursive SELECT
SELECT c.category_id, c.name FROM category c JOIN cte
ON cte.category_id=c.parent # find children
)
SELECT category_id, name FROM cte;
WITH RECURSIVE cte AS
(
SELECT category_id, name, 0 AS depth FROM category WHERE parent IS NULL
UNION ALL
SELECT c.category_id, c.name, cte.depth+1 FROM category c JOIN cte ON
cte.category_id=c.parent
)
SELECT * FROM cte ORDER BY depth;
WITH RECURSIVE cte AS
(
SELECT category_id, name, CAST(category_id AS CHAR(200)) AS path
FROM category WHERE parent IS NULL
UNION ALL
SELECT c.category_id, c.name, CONCAT(cte.path, ",", c.category_id)
FROM category c JOIN cte ON cte.category_id=c.parent
)
SELECT * FROM cte ORDER BY path;
#Finding all the leaf nodes
SELECT category_id, name FROM category
WHERE category_id NOT IN
# IDs of all parents:
(SELECT parent FROM category WHERE parent IS NOT NULL);
#Retrieving a Single Path
WITH RECURSIVE cte AS
(
SELECT name, parent FROM category WHERE name='FLASH'
UNION ALL
SELECT c.name, c.parent FROM category c JOIN cte
ON c.category_id=cte.parent # find parent
)
SELECT * FROM cte;
WITH RECURSIVE cte AS
(
SELECT name, parent, 0 as depth FROM category WHERE name='FLASH'
UNION ALL
SELECT c.name, c.parent, cte.depth-1 FROM category c JOIN cte
ON c.category_id=cte.parent
)
SELECT * FROM cte ORDER BY depth;
#Finding the Depth of the Nodes
WITH RECURSIVE cte AS
(
SELECT category_id, CAST(name AS CHAR(200)) AS name,
CAST(category_id AS CHAR(200)) AS path,
0 as depth
FROM category WHERE parent IS NULL
UNION ALL
SELECT c.category_id,
CONCAT(REPEAT(' ', cte.depth+1), c.name), # indentation
CONCAT(cte.path, ",", c.category_id),
cte.depth+1
FROM category c JOIN cte ON
cte.category_id=c.parent
)
SELECT * FROM cte ORDER BY path;
#Depth of a sub-tree
WITH RECURSIVE cte AS
(
SELECT category_id, name,
CAST(category_id AS CHAR(200)) AS path,
0 as depth
FROM category WHERE name='PORTABLE ELECTRONICS' # sub-tree root
UNION ALL
SELECT c.category_id,
c.name,
CONCAT(cte.path, ",", c.category_id),
cte.depth+1
FROM category c JOIN cte
ON cte.category_id=c.parent
)
SELECT * FROM cte ORDER BY path;
#Find the immediate subordinates of a node
WITH RECURSIVE cte AS
(
SELECT category_id, name, 0 as depth
FROM category WHERE name='PORTABLE ELECTRONICS'
UNION ALL
SELECT c.category_id, c.name, cte.depth+1
FROM category c JOIN cte
ON cte.category_id=c.parent
WHERE cte.depth=0
)
SELECT * FROM cte;
#Aggregate functions in a nested set
CREATE TABLE product(
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
parent INT DEFAULT NULL
);
INSERT INTO product VALUES(1,'ELECTRONICS',NULL),(2,'TELEVISIONS',1),(3,'TUBE',2),
(4,'LCD',2),(5,'PLASMA',2),(6,'PORTABLE ELECTRONICS',1),(7,'MP3 PLAYERS',6),(8,'FLASH',7),
(9,'CD PLAYERS',6),(10,'2 WAY RADIOS',6);
WITH RECURSIVE cte AS
(
SELECT c.category_id, c.name AS cat_name, c.parent, p.name AS prod_name
FROM category c JOIN product p ON c.category_id=p.category_id
UNION ALL
SELECT c.category_id, c.name, c.parent, cte.prod_name
FROM cte JOIN category c ON c.category_id=cte.parent
)
SELECT cat_name, COUNT(*) AS prod_in_cat FROM cte
GROUP BY cat_name;
################################################################################################
### PART 4 depth-first or breadth-first traversal, transitive closure, cycle avoidance
################################################################################################
#Depth-first or breadth-first
CREATE TABLE tree (person CHAR(20), parent CHAR(20));
INSERT INTO tree VALUES
('Robert I', NULL),
('Thurimbert', 'Robert I'),
('Robert II', 'Thurimbert'),
('Cancor', 'Thurimbert'),
('Landrade', 'Thurimbert'),
('Ingramm', 'Thurimbert'),
('Robert III', 'Robert II'),
('Chaudegrand', 'Landrade'),
('Ermengarde', 'Ingramm');
WITH RECURSIVE descendants AS
(
SELECT person
FROM tree
WHERE person='Thurimbert'
UNION ALL
SELECT t.person
FROM descendants d, tree t
WHERE t.parent=d.person
)
SELECT * FROM descendants;
WITH RECURSIVE descendants AS
(
SELECT person, 1 as level
FROM tree
WHERE person='Thurimbert'
UNION ALL
SELECT t.person, d.level+1
FROM descendants d, tree t
WHERE t.parent=d.person
)
SELECT * FROM descendants ORDER BY level;
WITH RECURSIVE descendants AS
(
SELECT person, CAST(person AS CHAR(500)) AS path
FROM tree
WHERE person='Thurimbert'
UNION ALL
SELECT t.person, CONCAT(d.path, ',', t.person)
FROM descendants d, tree t
WHERE t.parent=d.person
)
SELECT * FROM descendants ORDER BY path;
#Computing transitive closures with simple cycle avoidance
CREATE TABLE rockets
(origin CHAR(20), destination CHAR(20), trip_time INT);
INSERT INTO rockets VALUES
('Earth', 'Mars', 2),
('Mars', 'Jupiter', 3),
('Jupiter', 'Saturn', 4);
WITH RECURSIVE all_destinations AS
(
SELECT destination AS planet
FROM rockets
WHERE origin='Earth'
UNION ALL
SELECT r.destination
FROM rockets r, all_destinations d
WHERE r.origin=d.planet
)
SELECT * FROM all_destinations;
INSERT INTO rockets VALUES ('Saturn', 'Earth', 9);
WITH RECURSIVE all_destinations AS
(
SELECT destination AS planet
FROM rockets
WHERE origin='Earth'
UNION ALL
SELECT r.destination
FROM rockets r, all_destinations d
WHERE r.origin=d.planet
)
SELECT * FROM all_destinations;
#More complex cycle avoidance
WITH RECURSIVE all_destinations AS
(
SELECT destination AS planet, trip_time AS total_time,
CAST(destination AS CHAR(500)) AS path
FROM rockets
WHERE origin='Earth'
UNION ALL
SELECT r.destination, d.total_time+r.trip_time,
CONCAT(d.path, ',', r.destination)
FROM rockets r, all_destinations d
WHERE r.origin=d.planet
AND FIND_IN_SET(r.destination, d.path)=0
)
SELECT * FROM all_destinations;
WITH RECURSIVE all_destinations AS
(
SELECT destination AS planet, trip_time AS total_time,
CAST(destination AS CHAR(500)) AS path, 0 AS is_cycle
FROM rockets
WHERE origin='Earth'
UNION ALL
SELECT r.destination, d.total_time+r.trip_time,
CONCAT(d.path, ',', r.destination),
FIND_IN_SET(r.destination, d.path)!=0
FROM rockets r, all_destinations d
WHERE r.origin=d.planet
AND is_cycle=0
)
SELECT * FROM all_destinations;
with cte1(c1, c2) as
(select 1, '0' from dual
union all select 2, '1' from dual
),
cte2(c1, c2) as
(select '0', 1 from dual
union all select cte1.c2, cte1.c1 from cte2, cte1 where 10 = cte2.c1)
select * from cte1;
\ No newline at end of file
drop database if exists ctetest;
create database ctetest;
use ctetest;
create table EMP (
EMPno number,
ENAME varchar(30),
JOB varchar(30),
MGR number(4),
HIREDATE date,
SAL number(7,2),
COMM number(7,2),
DEPTNO number(2)
) ;
create table DEPT(
DEPTNO number(2),
DNAME char(45),
LOC varchar(39)
) ;
insert into EMP values (7369,'SMITH','CLERK',7902, str_to_date('17-DEC-80','%d-%b-%Y'),800,NULL, 20) ;
INSERT INTO EMP VALUES (7499, 'ALLEN','SALESMAN',7698,str_to_date('20-FEB-81','%d-%b-%Y'),1600,300,30) ;
INSERT INTO EMP VALUES (7521,'WARD','SALESMAN',7698, str_to_date('22-FEB-81','%d-%b-%Y'),1250, 500, 30) ;
INSERT INTO EMP VALUES (7566,'JONES','MANAGER',7839, str_to_date('02-APR-81','%d-%b-%Y'), 2975, NULL, 20) ;
INSERT INTO EMP VALUES (7654,'MARTIN','SALESMAN', 7698, str_to_date('28-SEP-81','%d-%b-%Y'), 1250, 1400, 30) ;
INSERT INTO EMP VALUES (7698, 'BLAKE','MANAGER', 7839, str_to_date('01-MAY-81','%d-%b-%Y'), 2850, NULL, 30) ;
INSERT INTO EMP VALUES (7782, 'CLARK','MANAGER', 7839, str_to_date('09-JUN-81','%d-%b-%Y'), 2450, NULL, 10) ;
insert into EMP values (7788,'SCOTT','ANALYST', 7566, str_to_date('19-APR-87','%d-%b-%Y'), 3000, null, 20) ;
INSERT INTO EMP VALUES (7839, 'KING','PRESIDENT', NULL, str_to_date('17-NOV-81','%d-%b-%Y'), 5000, NULL, 10) ;
INSERT INTO EMP VALUES (7844, 'TURNER','SALESMAN', 7698, str_to_date('08-SEP-81','%d-%b-%Y'), 1500, 0, 30) ;
INSERT INTO EMP VALUES(7876, 'ADAMS','CLERK', 7788, str_to_date('23-MAY-87','%d-%b-%Y'), 1100, NULL, 20) ;
INSERT INTO EMP VALUES(7900, 'JAMES', 'CLEARK', 7698, str_to_date('03-DEC-81','%d-%b-%Y'), 950, NULL, 30) ;
INSERT INTO EMP VALUES(7902, 'FORD','ANALYST',7566, str_to_date('03-DEC-81','%d-%b-%Y'), 3000, NULL, 20) ;
INSERT INTO EMP VALUES(7934,'MILLER','CLERK', 7782, str_to_date('23-JAN-82','%d-%b-%Y'), 1300,NULL, 10) ;
result_format: 4
## =======================================================================
## Test Case 1:
## - recursive WITH Query: Optimization on query with outside filter.
## Predicate pushdown optimization on static value job.
## The plan should reflect optimization or development can provide
## parameter to show that pushdown optimization happened for init branch
## =======================================================================
explain basic
WITH rw (ename, mgr, empno, job) AS
(
SELECT ename, mgr, empno, job
FROM emp e
UNION ALL
SELECT e.ename, e.mgr, e.empno, e.job
FROM rw r, emp e
WHERE r.empno = e.mgr
)
SELECT ename, empno, mgr, job
FROM rw
WHERE job = 'PRESIDENT' ;
WITH rw (ename, mgr, empno, job) AS
(
SELECT ename, mgr, empno, job
FROM emp e
UNION ALL
SELECT e.ename, e.mgr, e.empno, e.job
FROM rw r, emp e
WHERE r.empno = e.mgr
)
SELECT /*+ :HINT: */ ename, empno, mgr, job
FROM rw
WHERE job = 'PRESIDENT' ;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册