2012-06-29 29 views
6

Tôi có truy vấn sau đây để đếm tất cả dữ liệu mỗi phút.tổng cộng 3 hàng của một bảng

$sql= "SELECT COUNT(*) AS count, date_trunc('minute', date) AS momento 
FROM p WHERE fk_id_b=$id_b GROUP BY date_trunc('minute', date) 
ORDER BY momento ASC"; 

Điều tôi cần làm là tính tổng số cho mỗi hàng có tổng số 2 phút vừa qua.

For example with the result of the $sql query above 
|-------date---------|----count----| 
|2012-06-21 05:20:00 |  12  | 
|2012-06-21 05:21:00 |  14  | 
|2012-06-21 05:22:00 |  10  | 
|2012-06-21 05:23:00 |  20  | 
|2012-06-21 05:24:00 |  25  | 
|2012-06-21 05:25:00 |  30  | 
|2012-06-21 05:26:00 |  10  | 

I want this result: 

|-------date---------|----count----| 
|2012-06-21 05:20:00 |  12  | 
|2012-06-21 05:21:00 |  26  |  12+14 
|2012-06-21 05:22:00 |  36  |  12+14+10 
|2012-06-21 05:23:00 |  44  |  14+10+20 
|2012-06-21 05:24:00 |  55  |  10+20+25 
|2012-06-21 05:25:00 |  75  |  20+25+30 
|2012-06-21 05:26:00 |  65  |  25+30+10 
+0

Rất khó với SQL. Ứng dụng của bạn có thể thực hiện công việc không? Bạn phải lấy các hàng, và bạn có thể làm điều đó trong cùng một vòng lặp. – Searle

+0

@Parth Bhatt: Chỉnh sửa bạn đã phê duyệt rõ ràng là đặt ra một câu hỏi khác. Vui lòng không chấp thuận các chỉnh sửa đó. – interjay

+0

@interjay: Xin lỗi lỗi của tôi, tôi giải thích nó sai cách. –

Trả lời

10

này không phải là quá khó khăn với lag() window function (cũng trên SQL Fiddle):

CREATE TABLE t ("date" timestamptz, "count" int4); 
INSERT INTO t VALUES 
('2012-06-21 05:20:00',12), 
('2012-06-21 05:21:00',14), 
('2012-06-21 05:22:00',10), 
('2012-06-21 05:23:00',20), 
('2012-06-21 05:24:00',25), 
('2012-06-21 05:25:00',30), 
('2012-06-21 05:26:00',10); 

SELECT *, 
    "count" 
    + coalesce(lag("count", 1) OVER (ORDER BY "date"), 0) 
    + coalesce(lag("count", 2) OVER (ORDER BY "date"), 0) AS "total" 
    FROM t; 
  1. Tôi đã dụng dấu ngoặc kép datecount cột, vì đây là những từ dành riêng;
  2. lag(field, distance) cho tôi giá trị của các cột fielddistance cách dòng hiện tại, do đó chức năng đầu tiên cung cấp giá trị của hàng trước đó và cuộc gọi thứ hai cung cấp giá trị từ giá trị trước đó;
  3. coalesce() là cần thiết để tránh NULL kết quả từ lag() chức năng (đối với hàng đầu tiên trong truy vấn của bạn không có “trước” một, do đó nó NULL), nếu không total cũng sẽ NULL.
+0

Tuyệt vời! Tôi yêu các khái niệm về chức năng cửa sổ nhưng vẫn quên sử dụng chúng. Có một upvote :-) – Searle

+0

+1 cho giải pháp đúng. Tôi đã viết một câu trả lời, bởi vì bình luận là không đủ. –

9

@vyegorov's answer bao gồm chủ yếu. Nhưng tôi có nhiều hiểu biết hơn là phù hợp với một bình luận.

  1. Không sử dụng reserved words như datecount như định danh ở tất cả. PostgreSQL cho phép hai từ khóa cụ thể đó là định danh - khác với mọi tiêu chuẩn SQL. Nhưng nó vẫn còn thực hành xấu. Thực tế là bạn có thể sử dụng bất kỳ thứ gì bên trong dấu ngoặc kép làm số nhận dạng, thậm chí "; DELETE FROM tbl;" không làm cho nó trở thành ý tưởng hay. Tên "date" cho số timestamp gây hiểu lầm trên đầu trang đó.

  2. Loại dữ liệu sai. Ví dụ hiển thị timestamp, không phải timestamptz. Không tạo sự khác biệt ở đây, nhưng vẫn gây hiểu nhầm.

  3. Bạn không cần COALESCE(). Với window functions lag() and lead() bạn có thể có thể cung cấp một giá trị mặc định là tham số thứ 3:

xây dựng vào thiết lập này:

CREATE TABLE tbl (ts timestamp, ct int4); 
INSERT INTO tbl VALUES 
    ('2012-06-21 05:20:00', 12) 
, ('2012-06-21 05:21:00', 14) 
, ('2012-06-21 05:22:00', 10) 
, ('2012-06-21 05:23:00', 20) 
, ('2012-06-21 05:24:00', 25) 
, ('2012-06-21 05:25:00', 30) 
, ('2012-06-21 05:26:00', 10); 

Query:

SELECT ts, ct + lag(ct, 1, 0) OVER (ORDER BY ts) 
       + lag(ct, 2, 0) OVER (ORDER BY ts) AS total 
FROM tbl; 

Hoặc tốt hơn chưa : sử dụng một đơn sum() làm cửa sổ chức năng tổng hợp wi th a custom window frame:

SELECT ts, sum(ct) OVER (ORDER BY ts ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) 
FROM tbl; 

Kết quả tương tự.
liên quan:

+0

Giá trị mặc định cho 'lag' /' lead' là một giá trị tốt đẹp! – vyegorov

10

Dưới đây là một giải pháp tổng quát hơn cho tổng các giá trị từ hiện tại và N hàng trước (N = 2 trong trường hợp của bạn).

SELECT "date", 
sum("count") OVER (order by "date" ROWS BETWEEN 2 preceding AND current row) 
FROM t 
ORDER BY "date"; 

Bạn có thể thay đổi N từ 0 đến "Chưa được chuyển hướng". Cách tiếp cận này cung cấp cho bạn một cơ hội để có một tham số trong ứng dụng của bạn "đếm của N phút vừa qua". Ngoài ra, không cần xử lý các giá trị mặc định nếu ngoài giới hạn.

Bạn có thể tìm hiểu thêm về điều này trong tài liệu PostgreSQL (4.2.8. Window Function Calls)

+0

Đây là giải pháp tốt hơn câu trả lời được chấp nhận – user2259664

Các vấn đề liên quan