为什么这种递归连接会产生:数据太长

tri*_*cot 1 mysql varchar concat recursive-query

我在 MySQL 8 上有这个表:

create table tbl(id varchar(2), val int);
insert into tbl values ('A',  1), ('B',  2), ('C',  3), ('D',  4), ('E',  5);
Run Code Online (Sandbox Code Playgroud)

以下查询应找出哪些记录集的值加起来不大于 6(不考虑顺序):

with recursive cte(greatest_id, ids, total) as (
    select     id,
               concat(id, ''), 
               val
    from       tbl
    union all
    select     tbl.id,
               concat(cte.ids, tbl.id),
               cte.total + tbl.val
    from       cte 
    inner join tbl 
            on tbl.id > cte.greatest_id
           and cte.total + tbl.val <= 6
) 
select ids, total from cte
Run Code Online (Sandbox Code Playgroud)

运行它会导致以下错误:

错误:ER_DATA_TOO_LONG:concat(id, '')第 7行列的数据太长

为什么 MySQL 会产生这个错误?

有关信息,所需的输出如下:

 IDS | TOTAL
 ----+------
 A   |  1
 B   |  2
 C   |  3
 D   |  4
 E   |  5
 AB  |  3
 AC  |  4
 AD  |  5
 AE  |  6
 BC  |  5
 BD  |  6
 ABC |  6
Run Code Online (Sandbox Code Playgroud)

我想知道 MySQL 是通过哪个(记录的?)规则在这里产生这个错误的。

相比之下,该查询在 PostgreSQL 和 Oracle 上运行良好(使用它们的语法变体),所以我真的不明白为什么MySQL 会遇到问题。

Nic*_*ick 7

MySQL 8 CTE手册页的一个很长的例子显示了您遇到的问题。基本上问题在于,您的ids列对于ABC分配给它的值来说太窄了,因为它从 CTE 的非递归部分(实际上是id2 个字符的长度)获得宽度。您可以使用CAST足够大的宽度来解决该问题以适合所有结果,例如:

with recursive cte(greatest_id, ids, total) as (
    select     id,
               CAST(id AS CHAR(5)) AS ids, 
               val
    from       tbl
    union all
    select     tbl.id,
               concat(cte.ids, tbl.id),
               cte.total + tbl.val
    from       cte 
    inner join tbl 
            on tbl.id > cte.greatest_id
           and cte.total + tbl.val <= 6
) 
select ids, total from cte
Run Code Online (Sandbox Code Playgroud)

更新您的演示