Обновление полей различий на основе критериев в MySQL - PullRequest
0 голосов
/ 21 ноября 2018

Я храню в своей БД требования, которые могут выполнять некоторые пользователи.Требования могут иметь статус «Различия» (хранится как события), например, «В процессе», «Завершено», «Ожидание» и т. Д.Требования имеют разные сроки выполнения, соответствующие различным этапам обработки.

Мне нужно «заморозить» некоторые сроки выполнения требований, если их текущий статус относится к списку предварительно определенных.

Например:

  • Если спрос имеет статус "A", мне нужно «заморозить» крайний срок от 2 до 5.
  • Если статус "B" или "C", я должен «заморозить» крайний срок от 3 до 5.
  • Если статус "D", я должен «заморозить» крайний срок 4 и 5.

Я планирую использовать EVENT, который выполняется каждый день, в 19:00, чтобы обновить (добавить 1 день) различные сроки выполнения соответствующих требований.

Структуры таблиц:

Требование таблицы

id | someDatas | deadline1 | deadline2 | deadline3 | deadline4 | deadline5
---+-----------+-----------+-----------+-----------+-----------+-----------
   |           |           |           |           |           |

Состояние таблицы

id | name
---+-----
   |

События таблицы

id | id_demand | someOthersDatas | id_status
---+-----------+-----------------+----------
   |           |                 |

Я написалзапрос, чтобы получить требования, соответствующие списку статуса:

SELECT dem.*, st.`name` as 'statusName'
FROM `status` st
INNER JOIN `events` eve
    ON eve.id_status = st.id
INNER JOIN `demand` dem
    ON eve.id_demand = dem.id
WHERE st.`name` IN ('A', 'B', 'C', 'D')
    AND eve.id IN
    (
        SELECT MAX(even.id) ev
        FROM `demand` de
        INNER JOIN `events` even
            ON even.id_demand = de.id
        GROUP BY de.id
    );

Этот запрос работает отлично, и я могу получить необходимую информацию для моего лечения, у меня естьидентификатор требований, их сроки и название текущего статуса.

Я не против сохранить этот результат во временной таблице, такой как:

DROP TEMPORARY TABLE IF EXISTS pendingDemands;
CREATE TEMPORARY TABLE IF NOT EXISTS pendingDemands
SELECT /* the query shown above */

Чтобы убедиться, чтодень, который я хочу добавить к указанному сроку, действителен (= не выходной). Я написал функцию, которая вычисляет следующий действительный день:

DELIMITER //
DROP FUNCTION IF EXISTS `get_next_valid_date`;
CREATE FUNCTION `get_next_valid_date`(MyDate DATETIME) RETURNS DATETIME
BEGIN
    REPEAT
        SET MyDate = (DATE_ADD(MyDate, INTERVAL 1 DAY));
        SET @someCondition = (select isDayOff(MyDate));
    UNTIL (@someCondition = 0) END REPEAT;
    RETURN MyDate;
END//

Эта функция работает отлично, и я получаю ожидаемые результаты, и isDayOff() не нужно быть подробным.

Моя проблема в том, что я не знаю, как их использовать (временная таблица pendingDemands и функция get_next_valid_date) вместе для обновления таблицы demand Я не достаточно опытен в SQL, чтобы создавать такой красивый UPDATE запрос.

В каком направлении я могу пойти?

1 Ответ

0 голосов
/ 21 ноября 2018

Я наконец-то нашел решение, основанное на этом ответе

Я создал хранимую процедуру, в которой я использую курсор, сохраняющий запрос, который я использовал для подачи pendingDemandsвременная таблица.

Затем я зациклил курсор и использовал оператор CASE WHEN, чтобы определить изменяемые значения:

DELIMITER $$
DROP PROCEDURE IF EXISTS `freezePendingDeadlines` $$
CREATE PROCEDURE `freezePendingDeadlines`()
BEGIN
    -- from http://stackoverflow.com/questions/35858541/call-a-stored-procedure-from-the-declare-statement-when-using-cursors-in-mysql

    -- declare the program variables where we'll hold the values we're sending into the procedure;
    -- declare as many of them as there are input arguments to the second procedure,
    -- with appropriate data types.

    DECLARE p_id INT DEFAULT 0;
    DECLARE pT2P DATETIME DEFAULT NULL;
    DECLARE pT3P DATETIME DEFAULT NULL;
    DECLARE pT4P DATETIME DEFAULT NULL;
    DECLARE pT5P DATETIME DEFAULT NULL;
    DECLARE pstatusName VARCHAR(255) DEFAULT NULL;

    -- we need a boolean variable to tell us when the cursor is out of data

    DECLARE done TINYINT DEFAULT FALSE;

    -- declare a cursor to select the desired columns from the desired source table1
    -- the input argument (which you might or might not need) is used in this example for row selection

    DECLARE demandCursor
     CURSOR FOR
     SELECT p.id,
            p.T2P,
            p.T3P,
            p.T4P,
            p.T5P,
            P.statusName
       FROM
       (
           SELECT dem.*, st.`name` as 'statusName'
           FROM `status` st
           INNER JOIN `events` eve
               ON eve.id_status = st.id
           INNER JOIN `demand` dem
               ON eve.id_demand = dem.id
           WHERE st.`name` IN ('A', 'B', 'C', 'D')
               AND eve.id IN
               (
                   SELECT MAX(even.id) ev
                   FROM `demand` de
                   INNER JOIN `events` even
                       ON even.id_demand = de.id
                   GROUP BY de.id
               )
       ) AS p;

    -- a cursor that runs out of data throws an exception; we need to catch this.
    -- when the NOT FOUND condition fires, "done" -- which defaults to FALSE -- will be set to true,
    -- and since this is a CONTINUE handler, execution continues with the next statement.   

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    DROP TEMPORARY TABLE IF EXISTS days_off;
    CREATE TEMPORARY TABLE IF NOT EXISTS days_off
    (
        date_off VARCHAR(5)
    );

    INSERT INTO days_off VALUES('01-01'),
                               ('05-01'),
                               ('05-08'),
                               ('07-14'),
                               ('08-15'),
                               ('11-01'),
                               ('11-11'),
                               ('12-25');

    -- open the cursor

    OPEN demandCursor;

    my_loop: -- loops have to have an arbitrary label; it's used to leave the loop
    LOOP

      -- read the values from the next row that is available in the cursor

      FETCH demandCursor INTO p_id, pT2P, pT3P, pT4P, pT5P, pstatusName;

      IF done THEN -- this will be true when we are out of rows to read, so we go to the statement after END LOOP.
        LEAVE my_loop;
      ELSE
        CASE pstatusName
            WHEN 'A' THEN
                SET pT2P=get_next_valid_date(pT2P);
                SET pT3P=get_next_valid_date(pT3P);
                SET pT4P=get_next_valid_date(pT4P);
                SET pT5P=get_next_valid_date(pT5P);

            WHEN 'B' THEN
                SET pT3P=get_next_valid_date(pT3P);
                SET pT4P=get_next_valid_date(pT4P);
                SET pT5P=get_next_valid_date(pT5P);

            WHEN 'C' THEN
                SET pT3P=get_next_valid_date(pT3P);
                SET pT4P=get_next_valid_date(pT4P);
                SET pT5P=get_next_valid_date(pT5P);

            WHEN 'D' THEN
                SET pT4P=get_next_valid_date(pT4P);
                SET pT5P=get_next_valid_date(pT5P);
        END CASE;
        UPDATE `demand`
        SET T2P=pT2P,
            T3P=pT3P,
            T4P=pT4P,
            T5P=pT5P
        WHERE id=p_id;
      END IF;
    END LOOP;
    CLOSE demandCursor;
    DROP TEMPORARY TABLE IF EXISTS days_off;
END$$
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...