PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Função de janela do Postgres e grupo por exceção


Você não , na verdade, usando funções agregadas. Você está usando funções de janela . É por isso que o PostgreSQL exige sp.payout e s.buyin para ser incluído no GROUP BY cláusula.

Ao anexar um OVER cláusula, a função agregada sum() é transformado em uma função de janela, que agrega valores por partição enquanto mantendo todas as linhas.

Você pode combinar funções de janela e funções agregadas . As agregações são aplicadas primeiro. Não entendi na sua descrição como você deseja lidar com vários pagamentos / buy-ins por evento. Como um palpite, calculo uma soma deles por evento. Agora Posso remover sp.payout e s.buyin do GROUP BY cláusula e obter uma linha por player e 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;

Nesta expressão:sum(sum(sp.payout)) OVER w , a sum() externa é uma função de janela, a sum() interna é uma função agregada.

Supondo p.player_id e e.event_id são PRIMARY KEY em suas respectivas tabelas.

Eu adicionei e.event_id para o ORDER BY da WINDOW cláusula para chegar a uma ordem de classificação determinística. (Pode haver vários eventos na mesma data.) Também incluído event_id no resultado para distinguir vários eventos por dia.

Enquanto a consulta se restringe a um único player (WHERE p.player_id = 17 ), não precisamos adicionar p.name ou p.player_id para GROUP BY e ORDER BY . Se uma das junções multiplicasse as linhas indevidamente, a soma resultante seria incorreta (multiplicada parcial ou completamente). Agrupando por p.name não foi possível reparar a consulta então.

Eu também removi e.date do GROUP BY cláusula. A chave primária e.event_id cobre todas as colunas da linha de entrada desde o PostgreSQL 9.1.

Se você altera a consulta para retornar vários jogadores ao mesmo tempo, 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 é definido como único (?), grupo e ordem por player_id além disso, para obter resultados corretos em uma ordem de classificação determinística.

Eu só mantive e.date e p.name em GROUP BY ter ordem de classificação idêntica em todas as cláusulas, esperando um benefício de desempenho. Caso contrário, você pode remover as colunas de lá. (Semelhante para apenas e.date na primeira consulta.)