Let's say I have two tables. One is the orders table and the other is a price table giving the price of an item wrt the number of items ordered. The meaning of the test_price table is "up-to count items(inclusive) the cost per item is price ". So 0-50 items cost 1.22 per item. 51-100 cost 1.20 per item.
table test_price
id | count | price
----+-------+-------
1 | 50 | 1.22
2 | 100 | 1.20
3 | 150 | 1.19
4 | 200 | 1.18
5 | 300 | 1.10
table test_orders
id | count
----+-------
1 | 12
2 | 50
3 | 65
4 | 155
5 | 400
So this means that order 1 for 12 items should be priced at 1.22 per item. Order 5 should be priced at 1.10 per item.
I can get the price for a single order with
SELECT price FROM test_prices WHERE
count >= (SELECT count FROM test_orders WHERE id = 1)
ORDER BY count ASC LIMIT 1;
I would like to create a view that shows the orders with unit price and total price as columns
I think your test_prices
table is not quite right. I think it should be:
id | count | price
----+-------+-------
1 | 1 | 1.22
2 | 100 | 1.20
3 | 150 | 1.19
4 | 200 | 1.18
5 | 300 | 1.10
This says that for 1-99 quantity, the price is $1.22. For 100-149, the price $1.20, and so on.
With this structure, you can use a lateral join:
select o.*, p.price
from test_orders o left join lateral
(select p.*
from test_prices p
where p.count <= o.count
order by p.count desc
fetch first 1 row only
) p
on 1=1
Join the tables on the count
columns applying your conditions:
with cte as (select max(count) maxcount from test_price)
select
o.*, o.count * p.price total_price
from test_orders o inner join test_price p
on p.count = coalesce(
(select min(count) from test_price where o.count <= count),
(select maxcount from cte)
)
order by o.id;
See the demo .
Results:
| id | count | total_price |
| --- | ----- | ----------- |
| 1 | 12 | 14.64 |
| 2 | 50 | 61 |
| 3 | 65 | 78 |
| 4 | 155 | 182.9 |
| 5 | 400 | 440 |
The problem with your data is that price_table
data is not all "up-to count", because the 5th row also means "up-to and beyond". If you are able to add another row to price_table
like (6, 10000, 1.10)
then the solution is easy:
CREATE VIEW price_view AS
SELECT orders.id, orders.count, p.price, orders.count * p.price as total
FROM (
SELECT o.id, o.count, min(p.count) as pricebracket
FROM test_price p
LEFT JOIN test_orders o ON p.count >= o.count
GROUP BY o.id, o.count) orders
LEFT JOIN test_price p ON orders.pricebracket = p.count
ORDER BY orders.id
If you cannot get rid of this inconsistency in your data then you have to select maximum value first. So the query modifies like this:
CREATE VIEW price_view AS
WITH temptable as (SELECT max(p.count) as maxcount FROM test_price p)
SELECT orders.id, orders.count, p.price, orders.count * p.price as total
FROM (
SELECT o.id, o.count, min(p.count) as pricebracket
FROM test_price p
CROSS JOIN temptable
LEFT JOIN test_orders o ON p.count >=
(case when o.count > temptable.maxcount then temptable.maxcount else o.count end)
GROUP BY o.id, o.count) orders
LEFT JOIN test_price p ON orders.pricebracket = p.count
ORDER BY orders.id
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.