mysql - 为什么这个递归连接产生 : Data too long

标签 mysql concatenation varchar 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);

下面的查询应该找出哪些记录集的值加起来不大于 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

Running it导致以下错误:

Error: ER_DATA_TOO_LONG: Data too long for column concat(id, '') at row 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

我想知道 MySQL 是根据哪个(已记录?)规则在此处产生此错误的。

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

最佳答案

远低于 MySQL 8 CTE manual page是一个显示您遇到的问题的示例。基本上,问题是您的 ids 列对于分配给它的 ABC 值来说太窄了,因为它的宽度来自 CTE 的非递归部分(这是实际上是 id 的长度,即 2 个字符)。您可以使用 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

Update of your demo

关于mysql - 为什么这个递归连接产生 : Data too long,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54732559/

相关文章:

mysql - 触摸 MYSQL 记录以更新 TIMESTAMP 字段

string - Prolog 中的字符串串联

mysql - 在 rails 中为 MySQL 定义 varchar 的长度

sql - SQL 中字符串比较与 int 连接的性能

mysql - GROUP_CONCAT() 中的 CONCAT()

mySQL如何将NULL显示为0

java - StringBuilder 中的多个 StringBuilder。值得吗?

javascript - 将数组的每个项目与另一个数组的项目连接

mysql - 我想用一个查询替换从 "300-21-2"到 "300-21-02"的一列中的文本

mysql - 有没有办法镜像本地和在线的 MySQL 数据库?