MySQL获取所有行的总和而不检索所有行

时间:2014-08-13 13:52:51

标签: php mysql sql

这可能有点令人困惑,但请耐心等待。事情就是这样:

我有一个包含~1000条记录的数据库,如下表所示:

+------+----------+----------+
| id   | date     | amount   |
+------+----------+----------+
| 0001 | 14/01/15 |      100 |
+------+----------+----------+
| 0002 | 14/02/04 |      358 |
+------+----------+----------+
| 0003 | 14/05/08 |     1125 |
+------+----------+----------+

我想做的是:

  1. 检索从2014年开始直到昨天的所有记录:

    WHERE `date` > '14-01-01' AND `date` < CURDATE()
    
  2. 但是也可以得到amount到当前日期的总和,这是:

    WHERE `date` < CURDATE()
    
  3. 我已经通过根据第二个条件选择所有记录,获得总和,然后排除那些与第一个条件不匹配的记录来完成此工作。像这样:

    SELECT `id`, `date`, `amount` FROM `table`
    WHERE `date` < CURDATE()
    

    然后:

    $rows = fetchAll($PDOStatement);
    
    foreach($rows as $row) {
        $sum += $row->amount;
        if (
            strtotime($row->date) > strtotime('14-01-01') &&
            strtotime($row->date) < strtotime(date('Y-m-d'))
        ) {
            $valid_rows[] = $row;
        }
    }
    unset $rows;
    

    有效的方法是在单个查询中实现此目的吗? 事务比在PHP中整理记录更有效吗?这必须符合SQL标准(我将在MySQL和SQLite上执行此操作)。

    更新

    如果结果最终是这样的话无关紧要:

    +------+----------+----------+-----+
    | id   | date     | amount   | sum |
    +------+----------+----------+-----+
    | 0001 | 14/01/15 |      100 | 458 |
    +------+----------+----------+-----+
    | 0002 | 14/02/04 |      358 | 458 |
    +------+----------+----------+-----+
    | 0003 | 14/05/08 |     1125 | 458 |
    +------+----------+----------+-----+
    

    最糟糕的情况是,结果集合最终与给出总和的集合相同(在这种情况下,附加总和将是无关的并且会导致开销),但对于任何其他常规< / em>案例带宽保存将是巨大的。

5 个答案:

答案 0 :(得分:1)

编辑

您可以使用LEFT OUTER JOIN获取SUM。

    SELECT t1.`id`, t1.`date`, t2.sum_amount
    FROM
    `table` t1
    LEFT OUTER JOIN
    (
        SELECT SUM(`amount`) sum_amount
        FROM `table`
        WHERE `date` < CURDATE()
    ) t2
   ON 1 = 1
   WHERE t1.`date` > STR_TO_DATE('01,1,2014','%d,%m,%Y') AND t1.`date` < CURDATE();

答案 1 :(得分:1)

您可以使用总和创建特殊记录,并在第一个查询结束时添加

SELECT * FROM `table` WHERE `date` > '14-01-01' AND `date` < CURDATE()
UNION
SELECT 9999, CURDATE(), SUM(`amount`) FROM `table` WHERE `date` < CURDATE()

然后你将获得所有你想要的记录和id为9999的记录或者你的总和

答案 2 :(得分:1)

这可以通过相关子查询来实现,如下所示:

SELECT *, (SELECT SUM(amount) FROM t WHERE t.date < t1.date) AS PrevAmount
FROM        t AS t1
WHERE `date` > '14-01-01' AND `date` < CURDATE()

但是,如果记录数量很大,则效率非常低。

答案 3 :(得分:1)

这是hackish,但是:

> select * from foo;
+------+------+
| id   | val  |
+------+------+
|    1 |    1 |
|    2 |    2 |
|    3 |    3 |
|    4 |    4 |
|    5 |    5 |
+------+------+
5 rows in set (0.02 sec)

> select * from foo
left join (
    select sum(val)
    from foo
    where id < 3
) AS bar ON 1=1
where id < 4;
+------+------+----------+
| id   | val  | sum(val) |
+------+------+----------+
|    1 |    1 |        3 |
|    2 |    2 |        3 |
|    3 |    3 |        3 |
+------+------+----------+

基本上,在连接的子查询中进行求和。这会将总和结果附加到外表结果中的每一行。你会浪费一些带宽来发送每一行重复的值,但它确实可以让你得到一个单一的&#34;查询。

答案 4 :(得分:1)

这将做你想做的事情......优化子查询是真正的挑战:

SELECT id,date,amount,(SELECT SUM(amount) FROM table) AS total_amount
FROM table
WHERE date BETWEEN '14-01-01' AND DATE_ADD(CURDATE(), INTERVAL -1 DAY)