SQL-запрос для выбора, пока SUM (users_count) не достигнет 1000
Мне нужен sql-запрос для выбора строк из очереди сообщений, пока SUM (users_count) не достигнет не более 1000. НО нет проблем, если будет только одна строка, и эта строка users_count более 1000.
Мне нужно что-то вроде: (я добавил свои собственные ключевые слова)
SELECT * FROM `messages_queue` UNTIL SUM(users_count) < 1000 AT LEAST 1 ROW
Это моя структура таблицы:
messages_queue
- msg_id
- msg_body
- users_count (количество повторителей сообщений)
- время (время вставки)
Ответы
Ответ 1
Это решение будет выполнять кумулятивную сумму, останавливаясь, когда сумма превышает 1000:
SELECT NULL AS users_count, NULL AS total
FROM dual
WHERE (@total := 0)
UNION
SELECT users_count, @total := @total + users_count AS total
FROM messages_queue
WHERE @total < 1000;
Это означает, что если у вас есть два значения, скажем, 800, сумма будет равна 1600. Первый SELECT должен просто инициализировать переменную @total
.
Если вы хотите, чтобы сумма не превышала 1000, кроме случаев, когда одна строка имеет значение больше 1000, то я думаю, что это работает, хотя вам нужно подвергнуть ее строгому тестированию:
SELECT NULL AS users_count, NULL AS total, NULL AS found
FROM dual
WHERE (@total := 0 OR @found := 0)
UNION
SELECT users_count, @total AS total, @found := 1 AS found
FROM messages_queue
WHERE (@total := @total + users_count)
AND @total < 1000
UNION
SELECT users_count, users_count AS total, 0 AS found
FROM messages_queue
WHERE IF(@found = 0, @found := 1, 0);
Ответ 2
Я думаю, вы хотите сделать что-то вроде этого:
SELECT *
FROM
(SELECT
*
, (select sum(users_count) from `messages_queue` where time <= mq.time) RunningTotal
FROM `messages_queue` mq) mq2
WHERE mq2.RunningTotal < 1000
Ответ 3
Престижность Aducci для чистого SQL-решения, но, как сказал Томас Бергер, это может оказаться очень дорогостоящим запросом. В зависимости от размера вашей таблицы хранимая процедура может быть лучшим способом:
CREATE PROCEDURE messages_to_send
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE oldest_date DATETIME;
DECLARE cur_count INT;
DECLARE que_size INT DEFAULT 0;
DECLARE curs CURSOR FOR SELECT users_count, time FROM messages_que ORDER BY time;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN curs;
read_loop: LOOP
FETCH curs INTO cur_count, oldest_date;
IF done THEN
LEAVE read_loop;
END IF;
que_size = que_size + cur_count
IF que_size >= 1000
LEAVE read_loop;
END IF;
END LOOP;
CLOSE curs
SELECT * FROM messages_que WHERE time < oldest_date;
END
CALL messages_to_send(); --> returns a result set of messages to send with a total user_count of 1000 or less
Ответ 4
Я попытался добавить это как комментарий Майку, однако это проблематично с знаками @для переменных.
Чтобы нарисовать ответ Майка, запрос действительно мог быть сокращен путем инициализации переменной в предложении FROM, например:
SELECT users_count, @total := @total + users_count AS total
FROM (messages_queue, (select @total := 0) t)
WHERE @total < 1000;
Ответ 5
Я не думаю, что вы могли бы с этим простым MySQL Query.
Вам нужно будет использовать хранимую процедуру или фильтр, которые в вашем приложении.
ИЗМЕНИТЬ
Я не MySQL Guru (мог только код хранимых процедур в oracle и postgres), но вы могли бы начать здесь: http://www.mysqltutorial.org/sql-cursor-in-stored-procedures.aspx.
Более общая информация о синтаксисе находится здесь: http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html