Почему этот рекурсивный конкат производит: данные слишком длинные - PullRequest
0 голосов
/ 17 февраля 2019

У меня есть эта таблица на 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

Запуск его приводит к следующей ошибке:

Ошибка: 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

Я хочу знать, по какой (задокументировано?) правило MySQL выдает здесь эту ошибку.

Для сравнения, запрос отлично работает на PostgreSQL и Oracle (используя их синтаксическое изменение), поэтому я не совсем понимаю , почему MySQL имеетпроблема с этим.

1 Ответ

0 голосов
/ 17 февраля 2019

Длинный путь вниз по странице справки по MySQL 8 CTE - это пример, который показывает проблему, с которой вы столкнулись.В основном проблема в том, что ваш столбец 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

Обновление вашей демонстрации

...