MySQL添加总列

时间:2009-01-28 23:38:08

标签: sql mysql aggregate-functions subquery

我需要查询此DB以获取每一行,还要查询结果的一个列值的SUM。我可以使用php来获取总值,但是我需要运行两个循环,一个用于获取总数(在结果之上的顶部)。所以我更喜欢查询来捕获它并只是创建一个“总”行,但我唯一能让它工作的方法是使用一个子查询,它实质上是原始查询的重复。还有更好的方法吗?

SELECT 
CONCAT(u.firstname, ' ', u.lastname ) name, u.id, s.description, s.shiftstart, s.shiftend, 
    (SELECT 
    SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600
    FROM shifts
    WHERE id =  '$user'
    AND DATE( shiftstart )
    BETWEEN '$start'
    AND '$end') total
FROM shifts s
INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = '$user'
AND DATE( shiftstart )
BETWEEN '$start'
AND '$end'
ORDER BY shiftstart

上述作品和输出:

name        id     description  shiftstart             shiftend               total
Joe User    joeuser    Stuff    2009-01-05 07:45:00    2009-01-05 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-05 13:00:00    2009-01-05 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 07:45:00    2009-01-06 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 10:45:00    2009-01-06 12:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 13:30:00    2009-01-06 14:30:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 14:30:00    2009-01-06 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 09:45:00    2009-01-07 14:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 15:00:00    2009-01-07 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 08:00:00    2009-01-08 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 13:15:00    2009-01-08 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 07:45:00    2009-01-09 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 11:45:00    2009-01-09 15:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 15:15:00    2009-01-09 17:00:00    39.5000

这就是我需要的,但可能不是获得它的最好方法。

4 个答案:

答案 0 :(得分:5)

MySQL支持一种名为ROLLUP的特殊分组修饰符。

SELECT CONCAT(u.firstname, ' ', u.lastname ) name, u.id, 
  s.description, s.shiftstart, s.shiftend, 
  SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600 total
FROM shifts s INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = ? AND DATE( shiftstart ) BETWEEN ? AND ?
GROUP BY u.id, s.shiftstart WITH ROLLUP
ORDER BY shiftstart;

答案 1 :(得分:3)

更好的方法是使用代码执行此操作。人们一直坚持使用SQL(一种关系代数)来执行程序性任务。在复杂性和性能方面,试图将程序性过程强加于SQL是总是一个坏主意。接受专业DBA的建议。

从您的代码中运行两个查询。首先以您想要的任何格式输出较大的集合然后输出总行数。您的查询将更小更简单,您的表现将得到改善,您将获得所需的输出。

其他一些建议 - 磁盘空间很便宜,而且大多数数据库表的读取频率远远高于它们的写入时间。设置插入/更新触发器(如果可能在MySQL中)以使用计算字段(如“CONCAT(u.firstname,' ',u.lastname)”)填充单独的列,并将其用于查询。每行功能不可扩展,并且随着它变大而会破坏您的DBMS性能。

答案 2 :(得分:0)

相比之下,任何事情都可能更好;问题是与什么比较,对吗?

您指出的关键问题是您希望结果顶部的总数; Crystal Reports和其他应用程序通过成为2通道引擎来管理这种魔力。第一遍获得总数。

任何解决方案都需要权衡利弊。如果你得到一个单独的“总”行,那么接收应用程序将需要将其从结果中删除或者播放其他技巧来隐藏它。

如果你不是为一个100万次点击/小时的网站写作,可能是一种选择的一种可能性就是简单地进行2次调用 - 一次用于开销信息,例如名称,TOTAL Time等,然后是详细信息......从查询中可以看出,您选择的是单个人的结果。

我们都在节省开销和带宽,但有时候,简单就更好......

编辑:Pax打败了我的“保存”按钮...大笑......

答案 3 :(得分:0)

使用为此目的提供的mysql扩展名,如Bill Karwin的回复(我自己赞成)中所述。

如果这不可用,选项2将是另一个SQL语句:SELECT SUM ...)SQL实际上已经过优化,对于这类事情非常有效,与任何可能的程序代码循环相比写。