2011-02-18 17 views
16

Ok, en un principio esto era sólo una broma que tuvimos con un amigo mío, pero se convirtió en interesante cuestión técnica :)resultado de la función de ventana en PostgreSQL

Tengo el siguiente stuff tabla:

CREATE TABLE stuff 
(
    id serial PRIMARY KEY, 
    volume integer NOT NULL DEFAULT 0, 
    priority smallint NOT NULL DEFAULT 0, 
); 

La tabla contiene los registros de todas mis cosas, con el volumen y la prioridad respectivos (cuánto lo necesito).

Tengo una bolsa con el volumen especificado, por ejemplo 1000. Quiero seleccionar de la mesa todo lo que pueda poner en una bolsa, empacando las cosas más importantes primero.

Este parece ser el caso para el uso de funciones de la ventana, por lo que aquí es la pregunta que se me ocurrió:

select s.*, sum(volume) OVER previous_rows as total 
from stuff s 
where total < 1000 
WINDOW previous_rows as 
    (ORDER BY priority desc ROWS between UNBOUNDED PRECEDING and CURRENT ROW) 
order by priority desc 

El problema con él, sin embargo, es que Postgres se queja:

ERROR: column "total" does not exist 
LINE 3: where total < 1000 

Si elimino este filtro, la columna total se calcula correctamente, los resultados se ordenan correctamente, pero se seleccionan todas las cosas de, que no es lo que quiero.

Entonces, ¿cómo puedo hacer esto? ¿Cómo selecciono solo los artículos que pueden caber en la bolsa?

Respuesta

11

No he trabajado con PostgreSQL. Sin embargo, mi mejor opción sería usar una vista en línea.

SELECT a.* 
FROM (
    SELECT s.*, sum(volume) OVER previous_rows AS total 
    FROM stuff AS s 
    WINDOW previous_rows AS (
     ORDER BY priority desc 
     ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
    ) 
    ORDER BY priority DESC 
) AS a 
WHERE a.total < 1000; 
+0

Esto funciona bien. Me pregunto, sin embargo, si existe una solución más elegante. Es bastante extraño que no pueda filtrar en base al "total" directamente ... –

+1

Parece que las funciones de WINDOW no pueden usarse en WHERE, HAVING clause (así es como está en Oracle). Compruebe: http://www.postgresql.org/docs/current/static/tutorial-window.html – Chandu

11

No sé si esto califica como "más elegante", pero está escrito de una manera diferente a la solución de Cybernate (aunque es esencialmente la misma)

 
WITH window_table AS 
( 
    SELECT s.*, 
      sum(volume) OVER previous_rows as total 
    FROM stuff s 
    WINDOW previous_rows as 
     (ORDER BY priority desc ROWS between UNBOUNDED PRECEDING and CURRENT ROW) 
) 
SELECT * 
FROM window_table 
WHERE total < 1000 
ORDER BY priority DESC 

Si por "más "elegante" significa algo que evita la selección secundaria, entonces la respuesta es "no"

+1

Ok, gracias por su esfuerzo. Parece que una subconsulta de algún tipo es inevitable ... –

Cuestiones relacionadas