繁体   English   中英

一个 SQL 查询到 select 直到 SUM(users_count) 达到 1000

[英]A SQL query to select until SUM(users_count) reaches 1000

我需要一个 sql 查询到我的消息队列中的 select 行,直到 SUM(users_count) 最多达到 1000。但是如果只有一行返回并且该行的 users_count 大于 1000,则没有问题。

我需要类似的东西:(我添加了自己的关键字)

SELECT * FROM `messages_queue` UNTIL SUM(users_count) < 1000 AT LEAST 1 ROW

这是我的表结构:

消息队列
- msg_id
- msg_body
- users_count(消息接收者的数量)
- 时间(插入时间)

此解决方案将执行累积和,当总和超过 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);

我试图将此作为评论添加到 Mike 的答案中,但是,变量的 @ 符号存在问题。

为了借鉴 Mike 的回答,实际上可以通过在 FROM 子句中初始化变量来缩短查询,例如:

SELECT users_count, @total := @total + users_count AS total
    FROM (messages_queue, (select @total := 0) t)
WHERE @total < 1000;

我认为你正在寻找做这样的事情:

SELECT *
FROM
   (SELECT 
        *
      , (select sum(users_count) from `messages_queue` where time <= mq.time) RunningTotal       
   FROM `messages_queue` mq) mq2
WHERE mq2.RunningTotal < 1000

感谢 Aducci 的纯 SQL 解决方案,但正如 Thomas Berger 所说,这最终可能是一个非常昂贵的查询。 根据表的大小,存储过程很可能是更好的方法:

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

我认为您无法通过简单的 MySQL 查询来做到这一点。

您必须在应用程序中使用存储过程或过滤器。

编辑

我不是 MySQL Guru(只能在 oracle 和 postgres 上编写存储过程)但您可以从这里开始: http.aspin.mysql-tutorial.org/sql

有关语法的更多一般信息位于此处: http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM