MySQL 8 Recursive CTE Создать строку для каждого элемента - PullRequest
0 голосов
/ 26 октября 2019

Я хотел бы создать возврат данных из несуществующей таблицы:

+-------+--------+------------+
| type  | name   | expiration |
+-------+--------+------------+
| fruit | orange | 1999-12-31 |
| fruit | banana | 1999-12-31 |
| fruit | apple  | 1999-12-31 |
| fruit | orange | 2000-01-01 |
| fruit | banana | 2000-01-01 |
| fruit | apple  | 2000-01-01 |
+-------+--------+------------+

Где для каждого фрукта есть одна строка с одинаковой датой. Затем дата увеличивается на один день, и для этой даты создается строка для каждого фрукта.

Пока у меня есть такой запрос:

WITH RECURSIVE cte  
AS (
      SELECT 
          "fruit" as `type`
          ,"orange" as `name`
          ,"1999-12-31" as `expiration`
      UNION ALL
      SELECT 
          "fruit" as `type`
          ,"banana" as `name`
          ,date_add(`expiration`, INTERVAL 1 DAY) as `expiration`
      FROM cte 
      WHERE `expiration` < "2000-01-01"
    )
SELECT *
FROM cte
;

, который генерирует:

+-------+--------+------------+
| type  | name   | expiration |
+-------+--------+------------+
| fruit | orange | 1999-12-31 |
| fruit | banana | 2000-01-01 |
+-------+--------+------------+

Я думаю, что можно решить эту проблему, выполнив внутри рекурсивной таблицы CTE выбор из временной таблицы fruit_list, в которой есть имена фруктов, но я не знаю, как это реализовать.

Пример fruit_list таблица:

CREATE TEMPORARY TABLE IF NOT EXISTS `fruit_list` (
    `name` varchar(128) NOT NULL
) ENGINE = InnoDB;

INSERT INTO `fruit_list` VALUES
("orange")
,("banana")
,("apple")
;

Я хотел бы решить проблему с помощью обычного запроса вместо процедуры. Возможно ли это?

Цель решения состоит в том, чтобы иметь запрос, который может вернуть некоторые тестовые данные для каждого фрукта и диапазона дат.

Ответы [ 2 ]

1 голос
/ 26 октября 2019

Вы можете справиться с этим через серию перекрестных объединений:

SELECT
    f.type,
    n.name,
    e.expiration
FROM (SELECT 'fruit' AS type) f
CROSS JOIN
(
    SELECT 'orange' AS name UNION ALL
    SELECT 'banana' UNION ALL
    SELECT 'apple'
) n
CROSS JOIN
(
    SELECT '1999-12-31' AS expiration UNION ALL
    SELECT '2000-01-01'
) e
ORDER BY
    f.type,
    e.expiration,
    n.name;

screen capture of demo

Демо

0 голосов
/ 26 октября 2019

Для тех, кто хотел бы использовать временную таблицу, вот код:

CREATE TEMPORARY TABLE IF NOT EXISTS `fruit_list` (
    `name` varchar(128) NOT NULL
) ENGINE = InnoDB;

INSERT INTO `fruit_list` VALUES
("orange")
,("banana")
,("apple")
;

WITH RECURSIVE cte  
AS (
      SELECT 
        "1999-12-30" as `expiration`
      UNION ALL
      SELECT 
          date_add(`expiration`, INTERVAL 1 DAY) as `expiration`
      FROM cte 
      WHERE `expiration` < "2000-01-02"
    )
,cte1 as (
    SELECT * FROM cte
    CROSS JOIN `fruit_list`
)
SELECT     
    "fruit" as `type`
    ,`name`
    ,`expiration`
FROM cte1
ORDER BY
    `expiration`
    ,`name`
;

Результат:

+-------+--------+------------+
| type  | name   | expiration |
+-------+--------+------------+
| fruit | apple  | 1999-12-30 |
| fruit | banana | 1999-12-30 |
| fruit | orange | 1999-12-30 |
| fruit | apple  | 1999-12-31 |
| fruit | banana | 1999-12-31 |
| fruit | orange | 1999-12-31 |
| fruit | apple  | 2000-01-01 |
| fruit | banana | 2000-01-01 |
| fruit | orange | 2000-01-01 |
| fruit | apple  | 2000-01-02 |
| fruit | banana | 2000-01-02 |
| fruit | orange | 2000-01-02 |
+-------+--------+------------+
12 rows in set (0.00 sec)
...