2009-03-20 32 views
47

Tôi có truy vấn này MySQL:Tính tổng cộng chạy trong MySQL

SELECT DAYOFYEAR(`date`) AS d, COUNT(*) 
FROM `orders` 
WHERE `hasPaid` > 0 
GROUP BY d 
ORDER BY d 

nào trả về một cái gì đó như thế này:

d | COUNT(*) | 
20 | 5  | 
21 | 7  | 
22 | 12  | 
23 | 4  | 

Những gì tôi thực sự muốn một cột ở cuối dòng để hiển thị là chạy tổng số:

d | COUNT(*) | ??? | 
20 | 5  | 5 | 
21 | 7  | 12 | 
22 | 12  | 24 | 
23 | 4  | 28 | 

Điều này có thể?

+0

bản sao có thể có của [Tạo cột tổng tích lũy trong MySQL] (http://stackoverflow.com/questions/2563918/create-a-cumulative-sum-column-in-mysql) – Ztyx

+1

@Ztyx Câu hỏi được liên kết của bạn đã được hỏi hơn một năm sau đó. Vì vậy, nó sẽ là thay vì cách khác vòng. –

Trả lời

87

Có lẽ một giải pháp đơn giản hơn cho bạn và ngăn cơ sở dữ liệu phải thực hiện nhiều truy vấn. Điều này thực hiện chỉ một truy vấn sau đó thực hiện một phép toán nhỏ trên các kết quả trong một lần truyền.

SET @runtot:=0; 
SELECT 
    q1.d, 
    q1.c, 
    (@runtot := @runtot + q1.c) AS rt 
FROM 
    (SELECT 
     DAYOFYEAR(`date`) AS d, 
     COUNT(*) AS c 
    FROM `orders` 
    WHERE `hasPaid` > 0 
    GROUP BY d 
    ORDER BY d) AS q1 

Điều này sẽ cung cấp cho bạn một cột RT bổ sung (tổng chạy). Đừng bỏ lỡ câu lệnh SET ở trên cùng để khởi tạo biến tổng số đang chạy đầu tiên hoặc bạn sẽ chỉ nhận được một cột các giá trị NULL.

+1

hoạt động rực rỡ! Nhìn vào 'GIẢI THÍCH' về điều này cho thấy nó hiệu quả hơn nhiều so với câu trả lời được chấp nhận trước đây – nickf

+0

Điểm mấu chốt là sử dụng truy vấn phụ. Điều này làm cho nó đáng tin cậy trong các truy vấn phức tạp liên quan đến nhiều bảng hoặc tập hợp. –

+0

Đối với những người muốn làm một cái gì đó như thế này với các chức năng cơ bản của MySQL PHP, hãy chắc chắn để chạy dòng đầu tiên một cách riêng biệt (nhưng vẫn còn trước khi 2). –

1

Tôi sẽ nói rằng điều này là không thể mỗi hàng kết quả phải độc lập. Sử dụng ngôn ngữ lập trình để nhận các giá trị này

+0

Với tính chất của toán học quan hệ, và thực tế là bạn đang sử dụng nhóm theo, ngay cả khi mysql có một số hack để làm điều này có thể, nó sẽ ít phức tạp để chỉ làm điều đó trong một ngôn ngữ lập trình như Sergej gợi ý. –

+6

Tôi sẽ không đồng ý.Việc tách các nhiệm vụ xử lý giữa cơ sở dữ liệu và lớp ứng dụng là vấn đề từ góc độ tái sử dụng và bảo trì. Nếu bạn muốn sử dụng dữ liệu này ở những nơi khác nhau, có thể trên báo cáo và trên màn hình, bạn phải sao chép logic tổng số đang chạy. – cdonner

+0

+1 bạn đúng: điều này sẽ dễ dàng hơn và tổng thể hơn trong logic lập trình - tôi đã cố gắng xem liệu có một số chức năng tuyệt vời ma thuật để làm điều đó không. – nickf

9
SELECT 
    DAYOFYEAR(O.`date`) AS d, 
    COUNT(*), 
    (select count(*) from `orders` 
     where DAYOFYEAR(`date`) <= d and `hasPaid` > 0) 
FROM 
    `orders` as O 
WHERE 
    O.`hasPaid` > 0 
GROUP BY d 
ORDER BY d 

Điều này sẽ yêu cầu một số điều chỉnh cú pháp (Tôi không có MySQL để kiểm tra), nhưng nó cho bạn thấy ý tưởng. Truy vấn phụ chỉ cần quay trở lại và thêm tất cả mọi thứ mới mà bạn đã đưa vào truy vấn bên ngoài và nó phải làm điều đó cho mỗi hàng.

Hãy xem this question để biết cách sử dụng các kết nối để thực hiện tương tự.

Để giải quyết các mối quan tâm về suy thoái hiệu suất với dữ liệu đang phát triển: Vì có giá thầu CPC 366 ngày trong một năm và tôi cho rằng bạn không chạy truy vấn này trong nhiều năm, truy vấn phụ sẽ được đánh giá tối đa 366 lần. Với các chỉ số thích hợp vào ngày và cờ hasPaid, bạn sẽ ổn.

+0

- điều này hoạt động hoàn hảo như hiện nay. – nickf

+1

Hãy lưu ý rằng điều này sẽ rất chậm trên cơ sở dữ liệu lớn, trung bình và một số cơ sở dữ liệu nhỏ, vì nó cần phải thực hiện càng nhiều truy vấn bổ sung vì sẽ có các hàng trong kết quả –

+0

Đồng ý. Tôi đã +1 câu trả lời này vì nó rất thông minh và chúng tôi đã sử dụng tất cả các giải pháp như thế này khi cần thiết, nhưng chúng tôi cũng biết rằng có một chi phí. Phụ thuộc vào nơi bạn cần đếm. Đối với logic kinh doanh? Sau đó, có thể làm điều này trong DB. Để xem? Làm điều đó trong mã. –

1

Trừ khi bạn không có tùy chọn nào khác ngoài thực hiện điều này trong sql, tôi sẽ tính tổng kết quả bằng ngôn ngữ lập trình đang tạo truy vấn. Một cái lồng như thế này sẽ trở nên rất chậm khi cái bàn lớn lên.

+0

Hiệu suất sẽ phát triển với kích thước bảng, nhưng không mạnh do giá trị được tính và giữ lại. Các phương pháp khác dựa vào lựa chọn phụ sẽ đắt hơn. – Brendan

0

Bạn có thể hack điều này bằng cách sử dụng câu lệnh Cross Join hoặc một số tham gia slef nhưng nó sẽ bị chậm với bất kỳ tập dữ liệu lớn nào có lẽ được thực hiện tốt nhất trong bộ xử lý truy vấn bài; hoặc con trỏ của trong mã khách hàng

0

Đây là một trong những nơi duy nhất mà con trỏ là nhanh hơn so với một bộ dựa thắc mắc, nếu hiệu suất là rất quan trọng tôi sẽ hoặc

  • Do bên ngoài này của MySql hoặc
  • Sử dụng MySql 5 Cursors
Các vấn đề liên quan