Извлечение всех комбинаций из таблицы базы данных с альтернативными значениями

#php #mysql #sql #math

#php #mysql #sql #математика

Вопрос:

Допустим, у нас есть простая вкладка DB-table, созданная в MySQL с

 CREATE TABLE `tab` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `val` int(11) DEFAULT NULL,
 `altval` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`)
);
 

и заполняется набором данных examplary:

 INSERT INTO tab VALUES(1,1,NULL);
INSERT INTO tab VALUES(2,2,3);
INSERT INTO tab VALUES(3,4,NULL);
INSERT INTO tab VALUES(4,5,6);
 

Каждая строка имеет значение val, а для id=2,4 — альтернативное значение altval. Есть ли способ в SQL получить все комбинации для стандартных наборов данных? (Количество комбинаций равно 2 степени количества строк с альтернативными наборами данных, здесь: 4, поэтому ‘abitrary’, конечно, ограничено.) Для данного примера результат должен быть:
(1,2,4,5),(1,2,4,6),(1,3,4,5),(1,3,4,6)

На языке сценариев, таком как php, я бы решил эту проблему, создав вложенные циклы for с помощью eval() .

Комментарии:

1. Переосмысливая эту проблему, она также решаема с помощью рекурсивного программирования. Вероятно, это намного проще сделать, например, в php, а не в SQL.

Ответ №1:

Использование рекурсивного CTE:

 WITH RECURSIVE cte AS (
   -- continuous rn
   SELECT CAST(val AS CHAR(11)) val, CAST(altval AS CHAR(11)) AS altval,
          ROW_NUMBER() OVER(ORDER BY id) AS rn
   FROM tab
), rec AS (
  -- anchor
  SELECT val AS result, rn
  FROM cte
  WHERE rn = 1
  UNION ALL
  SELECT altval AS result, rn
  FROM cte
  WHERE rn = 1
    AND altval IS NOT NULL
  UNION ALL
  -- recursive part
  SELECT CONCAT(rec.result, ',', cte.val), cte.rn
  FROM rec
  JOIN cte ON cte.rn = rec.rn 1
  UNION ALL
  SELECT CONCAT(rec.result, ',', cte.altval), cte.rn
  FROM rec
  JOIN cte ON cte.rn = rec.rn 1
  WHERE cte.altval IS NOT NULL
)
SELECT result
FROM rec
WHERE rn = (SELECT COUNT(*) FROM cte);  -- choosing only longest string
 

db<>демо-версия скрипки

Комментарии:

1. Отлично! Это работает, но я не вижу, как добавить двоеточия в результат. В противном случае результат не может быть разделен однозначно для значений более 9.

2. @Stefan ` Я не вижу, как добавить двоеточия в результат. ` => CONCAT(rec.result, ',', cte.val)