Não consigo descobrir como escrever uma consulta que retorne uma soma contínua por item com base em regras de outra tabela.
Abaixo está uma tabela que lista em ordem cronológica o valor do estoque de um item em dias específicos.
Tabela 1: Estoque
item | estoque | data |
---|---|---|
Lâmina | 10 | 03/01/2020 |
Lâmina | 20 | 04/01/2020 |
Lâmina | 30 | 05/01/2020 |
Lâmina | 40 | 06/01/2020 |
Lâmina | 50 | 07/01/2020 |
Lâmina | 60 | 08/01/2020 |
Lâmina | 70 | 09/01/2020 |
Mesa | 10 | 03/01/2020 |
Mesa | 20 | 04/01/2020 |
Mesa | 30 | 05/01/2020 |
Mesa | 40 | 06/01/2020 |
Mesa | 50 | 07/01/2020 |
Mesa | 60 | 08/01/2020 |
Mesa | 70 | 09/01/2020 |
Outra tabela tem duas regras para cada item sobre quantos dias são usados para calcular os valores da soma contínua.
Tabela 2: Regra
item | regra | valor |
---|---|---|
Lâmina | soma_cum | 2,5 |
Lâmina | soma_de_leads | 2,5 |
Mesa | soma_cum | 3 |
Mesa | soma_de_leads | 3 |
Saída: cum_sum: Para Balde, data - 1/3/2020, a regra é 2,5 e, portanto, o valor = 10+20+30 * 0,5 lead_sum: Para Balde, data - 1/3/2020, a regra é 2,5 e, portanto, o valor = 20+30+40 * 0,5
Como escrevo a consulta para considerar valores parciais para a última data?
item | estoque | data | soma_cum | soma_de_leads |
---|---|---|---|---|
Lâmina | 10 | 03/01/2020 | 45 | 70 |
Lâmina | 20 | 04/01/2020 | 70 | 95 |
Lâmina | 30 | 05/01/2020 | 95 | 120 |
Lâmina | 40 | 06/01/2020 | 120 | 145 |
Lâmina | 50 | 07/01/2020 | 145 | 130 |
Lâmina | 60 | 08/01/2020 | 130 | 70 |
Lâmina | 70 | 09/01/2020 | 70 | 0 |
Mesa | 10 | 03/01/2020 | 60 | 90 |
Mesa | 20 | 04/01/2020 | 90 | 120 |
Mesa | 30 | 05/01/2020 | 120 | 150 |
Mesa | 40 | 06/01/2020 | 150 | 180 |
Mesa | 50 | 07/01/2020 | 180 | 130 |
Mesa | 60 | 08/01/2020 | 130 | 70 |
Mesa | 70 | 09/01/2020 | 70 | 0 |
https://sqlfiddle.com/postgresql/online-compiler?id=c87e6a47-0949-4781-b8b5-3559929a063d
Uma função de janela com uma moldura personalizada vem à mente, como:
Mas há duas questões :
_offset
a cláusula in the frame não permite variáveis._offset
a cláusula in the frame não processa números fracionários. Se você passar um tipo numérico com parte fracionária, ele será arredondado na conversão para inteiro. Isso é particularmente problemático com tipos de ponto flutuante comodouble precision
, onde 2,5 pode ser arredondado para 2 (!) devido ao armazenamento inexato do valor. (Eu não envolveria tipos de ponto flutuante nesses tipos de cálculo para começar!)O manual:
Para contornar o problema 1, faça um loop nos itens e execute SQL dinâmico em PL/pgSQL.
Para contornar o problema 2, trunque o limite superior e adicione outro valor
lead()
multiplicado pelo restante:Assumindo integridade referencial, e todas as colunas não
NOT NULL
e valores no intervalo permitido. Senão, você precisa fazer mais.violino
Solicite todos os itens:
Solicitação de itens fornecidos:
Certifique-se de ter um índice
stock(item)
para tornar isso rápido. Idealmente emstock(item, date) INCLUDE (stock)
, mas isso pode ser muito especializado.A função agregada
any_value()
foi adicionada com o Postgres 16. Substitua pormin()
em versões mais antigas. (E lembre-se de declarar sua versão do Postgres em todas as perguntas.)Produz seu resultado. Há sutilezas com arredondamento, tratamento de nulos, ordem de classificação e exibição, que a pergunta não esclareceu.