Как выбрать минимальную (дату) для набора значений, подобных этой таблице:
date status failure_time
-------------------------------------------------
2022-03-22 17:58:03 1 NULL
2022-03-22 18:00:03 0 NULL
2022-03-22 18:02:03 0 NULL
2022-03-22 18:04:03 1 6
2022-03-22 18:06:03 1 NULL
2022-03-22 18:08:03 0 NULL
2022-03-22 18:10:03 1 2
Моя попытка использовать этот триггер:
DECLARE LAST_STATUS integer;
DECLARE LAST_DATE datetime;
SET @LAST_STATUS := (SELECT `status` from crm ORDER by id DESC limit 1);
SET @LAST_DATE := (SELECT `date` from crm ORDER by id DESC limit 1);
IF (NEW.status = 1 and @LAST_STATUS = 0 ) THEN
SET NEW.`failure_time` := TIMESTAMPDIFF(MINUTE, @LAST_DATE , NEW.date) ;
END IF;
Дал результат вроде:
date status failure_time
-------------------------------------------------
2022-03-22 17:58:03 1 NULL
2022-03-22 18:00:03 0 NULL
2022-03-22 18:02:03 0 NULL
2022-03-22 18:04:03 1 2
2022-03-22 18:06:03 1 NULL
2022-03-22 18:08:03 0 NULL
2022-03-22 18:10:03 1 2
Я предполагаю, что нужно создать таблицу, которая работает как флаг и триггер, когда появится новый «ноль», я вставлю дату в эту таблицу, но мне не нужна эта работа.
Я знаю, что мне нужно получить дату первого «ноля» до «единицы», но я не знаю, как это сделать.
С каким действием связан триггер?
@Barmar перед вставкой.
Какую строку вы вставили, чтобы получить результат, который вы показываете?
@Barmar Я использую LAST_STATUS, чтобы проверить, есть ли у меня новый «один»
SELECT MIN(date) FROM crm
даст вам минимальную дату в таблице.
Вы нигде не используете LAST_STATUS
, вы используете только @LAST_STATUS
. Вы понимаете, что они не одинаковы?
@barmer, нет, нет, SELECT MIN(date) FROM crm дал мне первую дату таблицы, мне нужна первая дата, когда у меня есть первый ноль для набора нулей, если есть новая «1» эта дата исчезнет и примет другое значение, когда у меня будет новый нулевой набор.
Вы используете MySQL 8.x. Затем вы можете использовать оконную функцию LAG() для сравнения строк с предыдущей строкой.
@Barmar Можете ли вы использовать LAG() для поиска самой последней строки, если вы находитесь в триггере BEFORE INSERT и фактически еще не вставили новую строку?
В MySQL переменные, которые вы DECLARE, не имеют сигилы @
, и они являются локальными переменными, привязанными к триггеру или процедуре, в которой вы их объявляете. Переменные с сигилом @
вам не нужно объявлять (на самом деле это ошибка, если вы попытаетесь), и они привязаны к сеансу. Так что они совершенно разные. Многие люди путаются с MySQL, потому что в некоторых других продуктах SQL (кхм, Microsoft) синтаксис переменных отличается.
Я также рекомендую использовать синтаксис INTO
, чтобы вам не приходилось дважды выполнять запрос SELECT.
DECLARE LAST_STATUS INT;
DECLARE LAST_DATE DATETIME;
SELECT status, date INTO LAST_STATUS, LAST_DATE
FROM crm ORDER BY id DESC LIMIT 1;
IF (NEW.status = 1 and LAST_STATUS = 0 ) THEN
SET NEW.`failure_time` = TIMESTAMPDIFF(MINUTE, LAST_DATE , NEW.date) ;
END IF;
Оператор :=
следует записывать как =
, когда вы используете его в операторе SET
. Версия :=
используется, когда вы хотите выполнить присваивание как побочный эффект в выражении.
Я получил результат, перечитав снова и снова свой вопрос,
DECLARE LAST_STATUS INT;
DECLARE LAST_ONE_ID INT;
DECLARE FIRST_ZERO_DATE DATETIME;
select max(id) INTO LAST_ONE_ID from crm where status = 1 order by date desc;
select status INTO LAST_STATUS FROM crm ORDER BY id DESC LIMIT 1;
SELECT `date` INTO FIRST_ZERO_DATE from crm where id = ( LAST_ONE_ID + 1 ) ORDER by id DESC limit 1;
IF (NEW.status = 1 and LAST_STATUS = 0 ) THEN
SET NEW.`failure_time` := TIMESTAMPDIFF(SECOND, FIRST_ZERO_DATE , NEW.date) ;
END IF;
Я использую второй для теста, вот результат:
спасибо @Bill Karwin и @barmar за вашу помощь.
также я думаю, что есть некоторое улучшение предыдущего запроса.
Почему вы объявляете
LAST_STATUS
, но вместо этого используете@LAST_STATUS
?