#mysql #math
#mysql — сервер #математика #mysql
Вопрос:
Я хочу вычислить оценки для некоторых данных, которые у меня есть в базе данных MySQL. Оценка будет вычислена следующим образом:
score = COUNT(purchases MADE BETWEEN NOW() AND (NOW() - 1 WEEK))
0.7 * COUNT(purchases MADE BETWEEN (NOW() - 1 WEEK) AND (NOW() - 2 WEEKS))
0.4 * COUNT(purchases OLDER THAN (NOW() - 2 WEEKS))
У меня есть покупки в таблице со столбцом purchase_time.
Возможно ли сделать это в MySQL и получить вывод, подобный следующему?
ORDER_ID SCORE
3 8
4 3
5 15
Спасибо
— РЕДАКТИРОВАТЬ — Структура таблицы является:
tblOrder - table
id - primary key
created - time stamp
Комментарии:
1. можете ли вы указать структуру ваших таблиц и названия таблиц?
Ответ №1:
SELECT orderId,
SUM
(
CASE
WHEN purchase_date > NOW() - INTERVAL 1 WEEK AND purchase_date <= NOW() THEN
1
WHEN purchase_date > NOW() - INTERVAL 2 WEEK AND purchase_date <= NOW() - INTERVAL 1 WEEK THEN
0.7
ELSE
0.3
END
)
FROM mytable
GROUP BY
orderId
Комментарии:
1. 1 ты был быстрее 🙂 Однако я предлагаю, чтобы мой вариант был более оптимизирован, поскольку вычисление случая выполняется только один раз (конечно, это очень незначительное улучшение для систем, связанных с вводом-выводом, поскольку это влияет только на загрузку процессора, да и то незначительным образом)
2. Ах, это работает, потому что не использует count, только SUM, был введен в заблуждение комментарием выше о count, но sum (1) — хорошая альтернатива для count clever.
Ответ №2:
Ваши значения между и старше должны быть преобразованы в РЕГИСТР.
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
В то же время вы можете переписать выражение так, чтобы в конкретных случаях учитывались такие факторы, как
SELECT SUM(
CASE DATEDIFF(now(),purchase_datetime) DIV 7
WHEN 0 THEN 1
WHEN 1 THEN 0.7
ELSE 0.4
END
)
FROM table
WHERE purchase_datetime < now()
GROUP BY ORDER_ID
Комментарии:
1. Это должно быть
SUM
, неCOUNT
2. @Quassnoi — да, хорошее наблюдение. Я задавался вопросом, почему это не сработало. Спасибо @Unreason, это работает и проще, чем объединения :-).
Ответ №3:
SELECT ORDER ID, COUNT(purchases MADE BETWEEN NOW() AND (NOW() - 1 WEEK))
0.7 * COUNT(purchases MADE BETWEEN (NOW() - 1 WEEK) AND (NOW() - 2 WEEKS))
0.4 * COUNT(purchases OLDER THAN (NOW() - 2 WEEKS)) AS SCORE
FROM TABLE
должно сработать, в настоящее время у меня не установлен mysql, поэтому я не могу его протестировать.
кроме того, используйте datediff, чтобы определить, находится ли дата между диапазоном дат
Комментарии:
1. нет, это не поможет, COUNT поддерживает только COUNT (выражение) и COUNT (ОТЛИЧНОЕ выражение), см. dev.mysql.com/doc/refman/5.1/en /…
Ответ №4:
SELECT order_id, sum(score) FROM
(
(SELECT Order_id, COUNT(id) AS Score FROM purchases
WHERE purchase_time BETWEEN CURDATE() AND DATE_SUB(CURDATE(),INTERVAL 1 WEEK))
GROUP BY order_id
UNION ALL
(SELECT Order_id, (COUNT(id) * 0.7) AS score FROM purchases
WHERE purchase_time BETWEEN DATE_SUB(CURDATE(),INTERVAL 1 WEEK)
AND DATE_SUB(CURDATE(),INTERVAL 2 WEEK))
GROUP BY order_id
UNION ALL
(SELECT Order_id, (COUNT(id) * 0.4) AS score FROM purchases
WHERE purchase_time < DATE_SUB(CURDATE(),INTERVAL 2 WEEK))
GROUP BY order_id
) s
GROUP BY order_id;
Комментарии:
1. Йохан, обычно это просто неправильный подход. Ни один планировщик запросов не увидит, что он может получить то, что вы просите за одно сканирование, и выполнит три запроса и объединит их. Итак, если в purchase_time нет индекса, у вас будет запрос, который в 3 раза медленнее, чем должен быть (и в три раза сложнее). Кроме того, вы округляете данные слишком рано (если округление вообще необходимо).
2. @Unisoron, объединение не очень, я согласен, хотелось бы увидеть решение без объединения, исправлено раннее округление.
3. спасибо за усилия. Я пробовал это, но не смог заставить это работать, а другие подходы выглядят более эффективными.
4. В ответах Quassnoi и моих не используется объединение. @Paul J, этот подход в конечном итоге сработал бы, просто не так эффективен.