2010-11-04 34 views
14

Vì vậy, tôi đã có một tập hợp các kết quả mà trông giống như sau:MySQL: Cách SUM() một TIMEDIFF() trên một nhóm?

SELECT User_ID, StartTime, EndTime, TIMEDIFF(EndTime, StartTime) AS TimeDiff 
FROM MyTable 

------------------------------------------------------------------ 
| User_ID |  StartTime  |   EndTime  | TimeDiff | 
------------------------------------------------------------------ 
| 1 | 2010-11-05 08:00:00 | 2010-11-05 09:00:00 | 01:00:00 | 
------------------------------------------------------------------ 
| 1 | 2010-11-05 09:00:00 | 2010-11-05 10:00:00 | 01:00:00 | 
------------------------------------------------------------------ 
| 2 | 2010-11-05 06:30:00 | 2010-11-05 07:00:00 | 00:30:00 | 
------------------------------------------------------------------ 
| 2 | 2010-11-05 07:00:00 | 2010-11-05 09:00:00 | 02:00:00 | 
------------------------------------------------------------------ 
| 2 | 2010-11-05 09:00:00 | 2010-11-05 10:00:00 | 01:00:00 | 
------------------------------------------------------------------ 

Bây giờ tôi cần phải nhóm kết quả theo User_IDSUM() TimeDiff. Nếu tôi thêm mệnh đề GROUP BY, nó không SUM() TimeDiff (và tôi sẽ không mong đợi nó). Làm thế nào tôi có thể SUM() TimeDiffs cho mỗi Người dùng?

Trả lời

30

Sử dụng:

SELECT t.user_id,  
     SEC_TO_TIME(SUM(TIME_TO_SEC(t.endtime) - TIME_TO_SEC(t.starttime))) AS timediff 
    FROM MYTABLE t 
GROUP BY t.user_id 

bước:

  1. Sử dụng TIME_TO_SEC để chuyển đổi LÚC NÀO đến giây cho hoạt động toán học
  2. Sum sự khác biệt
  3. Sử dụng SEC_TO_TIME để chuyển đổi các giây trở lại LÚC NÀO

Dựa trên các dữ liệu mẫu, tôi muốn vừa đề nghị:

SELECT t.user_id,  
     TIMEDIFF(MIN(t.startdate), MAX(t.enddate)) AS timediff 
    FROM MYTABLE t 
GROUP BY t.user_id 

LƯU Ý: Có một lỗi trong mã này nếu bạn đang sử dụng datetime. TIME_TO_SEC chỉ chuyển đổi phần thời gian để bạn kết thúc với một số lớn âm nếu đồng hồ trôi qua nửa đêm. Sử dụng UNIX_TIMESTAMP thay vì để thực hiện tổng. Ngoài ra, SEC_TO_TIME maxes out tại các giá trị lớn hơn 3020399 giây, ví dụ: CHỌN TIME_TO_SEC (SEC_TO_TIME (3020400)); Nếu bạn xem giá trị này 838: 59: 59, bạn đã đạt đến giá trị tối đa và có thể chỉ cần để chia cho 3600 để chỉ hiển thị giờ.

+0

Chết tiệt, lẽ ra nên biết về 'TIME_TO_SEC' trước đó, tôi và kludgy của tôi' CONCAT' với ngày ngẫu nhiên .... +1 cho bạn! – Wrikken

+0

@Wrikken: dấu thời gian epoch không hoạt động tốt như vậy, vì vậy tôi đã phải ứng biến :) –

+0

xin lỗi, tôi cần phải cụ thể hơn. Thời gian bắt đầu/kết thúc thực sự là datetimes. Điều đó có thay đổi câu trả lời của bạn không? – Andrew

1

Nó có phù hợp với bạn không?

SELECT User_ID, TIME(SUM(TIMEDIFF(EndTime, StartTime))) AS TimeDiff
FROM MyTable GROUP BY User_ID

+1

AFAIK, 'SUM' trên giá trị' TIME' cho kết quả khó chịu ('01:30 + 02: 42' trở thành '0130 + 0242' => '0372' => thời gian không hợp lệ/NULL – Wrikken

+1

Wrikken là chính xác - Tôi đã nhận được kết quả là null khi kiểm tra điều này dựa trên dữ liệu mẫu. –

+0

+1 Bạn là người đúng.Đúng đoán, tôi đã thử nó và nó đã làm việc đúng nếu sự khác biệt không có phần phút/giây.Tôi bỏ lỡ thời điểm đó cũng có thể có phút/giây: ( – a1ex07

2

AFAIK, lựa chọn duy nhất của bạn là để cast để UNIX_TIMESTAMP s và làm một số tính toán số nguyên, thay thế một ngày ngẫu nhiên (tôi đã chọn 2000/01/01) cho các cột LÚC NÀO mà không có một ngày.

SELECT TIMEDIFF(
    DATE_ADD('2000-01-01 00:00:00', 
     INTERVAL 
     SUM(UNIX_TIMESTAMP(CONCAT('2000-01-01 ',TimeDiff)) - UNIX_TIMESTAMP('2000-01-01 00:00:00') 
     SECOND), 
    '2000-01-01 00:00:00') 
FROM MyTable; 

Bởi vì nó có thể vẻ bạn có thể SUM cột TIME, nhưng thực sự họ sẽ được đúc để số nguyên khó chịu hoặc nổi mà sẽ không làm theo thông số kỹ thuật thời gian (thử nó với một khoản phút> 60 và bạn sẽ hiểu ý tôi chứ).


Đối với những người khẳng định bạn có thể SUM cột thời gian:

mysql> create table timetest(a TIME); 
Query OK, 0 rows affected (0.00 sec) 

mysql> INSERT INTO timetest VALUES ('02:00'),('03:00'); 
Query OK, 2 rows affected (0.00 sec) 
Records: 2 Duplicates: 0 Warnings: 0 

mysql> SELECT SUM(a) FROM timetest; 
+--------+ 
| SUM(a) | 
+--------+ 
| 50000 | 
+--------+ 
1 row in set (0.00 sec) 

mysql> SELECT TIME(SUM(a)) FROM timetest; 
+--------------+ 
| TIME(SUM(a)) | 
+--------------+ 
| 05:00:00  | 
+--------------+ 
1 row in set (0.00 sec) 

mysql> -- seems ok, but wait 
mysql> INSERT INTO timetest VALUES ('02:30'); 
Query OK, 1 row affected (0.01 sec) 

mysql> SELECT TIME(SUM(a)) FROM timetest; 
+--------------+ 
| TIME(SUM(a)) | 
+--------------+ 
| 07:30:00  | 
+--------------+ 
1 row in set (0.00 sec) 

mysql> -- and now, oh ye unbelievers: 
mysql> INSERT INTO timetest VALUES ('01:40'); 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT TIME(SUM(a)) FROM timetest; 
+--------------+ 
| TIME(SUM(a)) | 
+--------------+ 
| NULL   | 
+--------------+ 
1 row in set, 1 warning (0.00 sec) 

mysql> -- why is that? because it uses integer arithmetic, not time - arithmetic: 
mysql> SELECT SUM(a) FROM timetest; 
+--------+ 
| SUM(a) | 
+--------+ 
| 87000 | 
+--------+ 
1 row in set (0.00 sec) 

mysql> -- that cannot be cast to time 
+1

Không, nó sẽ không. Tôi sẽ chỉnh sửa trong một ví dụ mà có phút không lên đến '0' trong nó trong một thời điểm. – Wrikken

+1

Vâng, tôi xấu, tôi đã không mất đủ thời gian để thấy rằng 1:59 + 1:59 không bằng 3:18: -p. –

+0

Hehe, ở đây, nó ổn, bạn có thể tin rằng tôi đã có một hệ thống bảng lương chạy trên giả định không chính xác này trong vài tuần một thời gian dài trước đây? Đám đông giận dữ tất cả xung quanh :) – Wrikken

0

tôi sẽ đề nghị bạn sử dụng TO_SECONDS thay vì:

SELECT t.user_id,  
     SEC_TO_TIME(SUM(TO_SECONDS(t.endtime) - TO_SECONDS(t.starttime))) AS timediff 
    FROM MYTABLE t 
GROUP BY t.user_id 
Các vấn đề liên quan