Sup. Noob dev here.
I have one table that stores ITEMS and another with PRICES.
Prices one is multiple rows per item, if someone updates the price it appends the table with another row with the date that the price will be valid. So if I need to know the current price I have to look for the max(date) where date<=now().
The problem is, I need to build a view to integrate an API with the last price, and can’t figure out a way to do it efficiently because every way I try the query takes 1~2 min to result (we are talking about 250k items and a lot of history prices)
- I’ve already tried a lateral join:
SELECT i.item,
i.unidade,
l.empresa,
l.valor,
l.dtvalida
FROM itens i
JOIN LATERAL (
SELECT t.empresa,
t.tabela,
t.tipo,
t.codigo,
t.unidade,
t.dtvalida,
t.valor,
t.valormin
FROM tpreco t
LEFT JOIN paemp pa ON t.empresa = pa.empresa
WHERE t.codigo = i.item AND t.tabela::text = pa.fattabavis::text
AND t.empresa = 1265 AND t.unidade::text = i.unidade::text
AND t.dtvalida <=now()
ORDER BY t.dtvalida DESC
LIMIT 1) l ON true
This does a good job showing results when I have low number of items, once I scale it takes very long.
- Tried a very junky way
select i.item,
i.descricao,
i.unidade,
ei.empresa,
t1.valor,
t1.dtvalida
From itens i
left join empitens ei on ei.item = i.item and (ei.precocodificado<>'S')
left join paemp p on p.empresa = ei.empresa
join tpreco t1 on t1.codigo = i.item
and t1.empresa = ei.empresa
and t1.tabela = p.fattabavis
and t1.unidade = i.unidade
and t1.dtvalida = (
select max(t2.dtvalida)
from tpreco t2
where t2.codigo = t1.codigo
and t2.empresa = t1.empresa
and t2.tabela = t1.tabela
and t2.unidade = t1.unidade
)
Same problem, surprisingly this works very well on low items count, but high not.
And tried a function to calculate this price, but when I call it in the other view (where I originally use the current price) it also took too long
create function ult_preco_f(_emp bigint, _tab varchar, _item bigint, _un varchar)
returns float
language plpgsql
as
$$
declare
last_valor float;
begin
select valor
into max_valor
from tpreco
where empresa = _emp
and tabela = _tab
and codigo = _item
and unidade = _un
and dtvalida<=now()
order by dtvalida desc
limit 1;
return last_valor;
end;
$$;
Ty to anyone willing to help.
2
Answers
You should use group by clause.
Assuming that tpreco.dtvalida is a date of processing order and tpreco.codigo is the item code, so the last order would be the following query
Then you can join these rows with original table to get the other values of the same rows using INNER JOIN.
And finally you can join this with your table itens.
I think you can also use another aggregate function (https://www.postgresql.org/docs/current/tutorial-agg.html) with order by, but that was the best solution I could think.
As idea, find latest price with row_number().
Try
OR
Possible join
paemp
after calculation of last price. Then search for last price simplified and may be, faster with proper index ontpreco
table.I don’t know table structure and links. Thats an idea only.