2012-06-29 23 views
6

Tengo la siguiente consulta para contar todos los datos por minuto.suma cada 3 filas de una tabla

$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"; 

Lo que necesito hacer es obtener la suma del recuento de cada fila con el recuento de los 2 minutos pasados.

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

muy complicado con SQL. ¿Tu aplicación no puede hacer el trabajo? Tienes que buscar las filas de todos modos, y podrías hacer eso en el mismo ciclo. – Searle

+0

@Parth Bhatt: la edición que aprobó claramente hace una pregunta diferente. Por favor, no apruebe tales ediciones. – interjay

+0

@interjay: Lo siento, error, lo interpreté de la manera incorrecta. –

Respuesta

10

Esto no es tan difícil con lag() window function (también en 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. tengo entre comillas dobles date y count columnas, ya que estas son palabras reservadas;
  2. lag(field, distance) me da el valor de field columna filas distance filas alejadas de la actual, por lo que la primera función da el valor de la fila anterior y la segunda llamada da el valor de la anterior;
  3. coalesce() se requiere para evitar NULL resultado de lag() función (por la primera fila de la consulta no hay “anterior” uno, por lo que es NULL), de lo contrario el total También habrá NULL.
+0

¡Excelente! Me encanta el concepto de funciones de ventana, pero sigo olvidando usarlas. Tener un voto positivo :-) – Searle

+0

+1 para la solución correcta. Escribí una respuesta porque el comentario no es suficiente. –

9

@vyegorov's answer lo cubre en su mayoría. Pero tengo más quejas que encajar en un comentario.

  1. No utilice reserved words como date y count como identificadores en absoluto. PostgreSQL permite esas dos palabras clave particulares como identificador, que no sean todos los estándares SQL. Pero sigue siendo una mala práctica. El hecho de que puede usar cualquier cosa dentro de comillas dobles como identificador, incluso "; DELETE FROM tbl;" no lo hace una buena idea. El nombre "date" para un timestamp es engañoso además de eso.

  2. Tipo de datos incorrecto. El ejemplo muestra timestamp, no timestamptz. No hace la diferencia aquí, pero sigue siendo engañoso.

  3. No necesita COALESCE(). Con la window functions lag() and lead() puede puede proporcionar un valor por defecto como tercera parámetro:

Sobre la base de esta configuración:

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); 

Consulta:

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

O mejor todavía : utilice un solo sum() como función agregada de ventana wi th a custom window frame:

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

Mismo resultado.
relacionadas:

+0

El valor predeterminado para 'lag' /' lead' es bueno! – vyegorov

10

Aquí hay una solución más general para la suma de los valores de corriente y N filas anteriores (N = 2 en su caso).

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

Puede cambiar N entre 0 y "Sin límites". Este enfoque le da la oportunidad de tener un parámetro en su aplicación "recuento de los últimos N minutos". Además, no es necesario manejar valores predeterminados si está fuera de límites.

Usted puede encontrar más información sobre esto en la documentación de PostgreSQL (4.2.8. Window Function Calls)

+0

Esta es una solución mejor que la respuesta aceptada – user2259664

Cuestiones relacionadas