sql >> Base de Datos >  >> RDS >> PostgreSQL

Función de ventana de Postgres y grupo por excepción

Usted no , de hecho, usando funciones agregadas. Está utilizando funciones de ventana . Es por eso que PostgreSQL exige sp.payout y s.buyin para ser incluido en el GROUP BY cláusula.

Agregando un OVER cláusula, la función agregada sum() se convierte en una función de ventana, que agrega valores por partición mientras mantiene todas las filas.

Puede combinar funciones de ventana y funciones agregadas . Las agregaciones se aplican primero. No entendí a partir de su descripción cómo desea manejar múltiples pagos/compras por evento. Como suposición, calculo una suma de ellos por evento. Ahora Puedo eliminar sp.payout y s.buyin del GROUP BY cláusula y obtener una fila por player y event :

SELECT p.name
     , e.event_id
     , e.date
     , sum(sum(sp.payout)) OVER w
     - sum(sum(s.buyin  )) OVER w AS "Profit/Loss" 
FROM   player            p
JOIN   result            r ON r.player_id     = p.player_id  
JOIN   game              g ON g.game_id       = r.game_id 
JOIN   event             e ON e.event_id      = g.event_id 
JOIN   structure         s ON s.structure_id  = g.structure_id 
JOIN   structure_payout sp ON sp.structure_id = g.structure_id
                          AND sp.position     = r.position
WHERE  p.player_id = 17 
GROUP  BY e.event_id
WINDOW w AS (ORDER BY e.date, e.event_id)
ORDER  BY e.date, e.event_id;

En esta expresión:sum(sum(sp.payout)) OVER w , el exterior sum() es una función de ventana, el sum() interno es una función agregada.

Asumiendo p.player_id y e.event_id son PRIMARY KEY en sus respectivas tablas.

Agregué e.event_id al ORDER BY de la WINDOW cláusula para llegar a un orden de clasificación determinista. (Puede haber varios eventos en la misma fecha). También se incluye event_id en el resultado para distinguir múltiples eventos por día.

Mientras que la consulta se restringe a un único jugador (WHERE p.player_id = 17 ), no necesitamos agregar p.name o p.player_id a GROUP BY y ORDER BY . Si una de las combinaciones multiplicara filas indebidamente, la suma resultante sería incorrecta (multiplicada parcial o totalmente). Agrupación por p.name entonces no se pudo reparar la consulta.

También eliminé e.date del GROUP BY cláusula. La clave principal e.event_id cubre todas las columnas de la fila de entrada desde PostgreSQL 9.1.

Si cambia la consulta para devolver varios jugadores a la vez, adapte:

...
WHERE  p.player_id < 17  -- example - multiple players
GROUP  BY p.name, p.player_id, e.date, e.event_id  -- e.date and p.name redundant
WINDOW w AS (ORDER BY p.name, p.player_id, e.date, e.event_id)
ORDER  BY p.name, p.player_id, e.date, e.event_id;

A menos que p.name se define único (?), grupo y orden por player_id adicionalmente para obtener resultados correctos en un orden de clasificación determinista.

Solo conservé e.date y p.name en GROUP BY tener un orden de clasificación idéntico en todas las cláusulas, esperando un beneficio de rendimiento. De lo contrario, puede eliminar las columnas allí. (Similar para solo e.date en la primera consulta.)