简体   繁体   中英

Creating view from item table and price table

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM