SQL Pricing Tiers - mysql

I have a pricing lookup table in MySQL where I need to lookup the right pricing based on the transaction quantity.
Say for example, i have a pricing table pricing, looks like:
product quantity price
prod1 1 4
prod1 10 3
prod1 100 2
prod1 1000 1
prod2 1 0.4
...
And I have a table called transaction where contains the sales data:
product sales
prod1 144
prod2 2
...
How can I get the sales multiply by the right unit price based on the quantity.
Something likes:
product sales quantity unitPrice
prod1 144 100 2
prod2....
I tried to join two table on product but don't know where to go from there.

One way to get the price is using a correlated subquery:
select t.*,
(select p.price
from pricing p
where p.product = t.product and p.quantity >= t.quantity
order by p.quantity
limit 1
) as price
from transaction t;
A similar subquery can be used to get other information such as the pricing tier.
For performance, you want an index on pricing(product, quantity).

Related

Best way to get list of element combinations from two mysql tables

I have two tables:
Table "products"
ID
Name
Price
Quantity
1
Product A
10
10
2
Product B
20
10
Table "promotions"
ID
Product ID
Type
Price
Quantity
1
1
discount
5
3
2
1
discount
8
2
3
1
outlet
10
3
4
2
outlet
10
0
From tables above I can see that:
I have 10 pieces of Product A with regular price 10$
I have 3 pieces of Product A with discounted price 5$
I have 2 pieces of Product A with discounted price 8$
I have 3 pieces of Product A with outlet price 3$
I have 10 pieces of Product B with regular price 20$
I have 0 pieces of Product B with outlet price 3$.
What is the most efficient way to get all combinations of available products?
My solution was with three UNION SQL querys, for example:
SELECT * FROM (
(<<all products in reular prices>>)
UNION ALL
(<<all products in discount prices>>)
UNION ALL
(<<all products in outlet prices>>)
) as tmp
Everything works fine, I am just wondering if this is the best way or is it better to use LEFT or RIGHT JOIN. Of course this is just an example, my tables have 20.000+ lines so I am looking for fastest way to list results.
One option could be:
first apply a UNION between "Products" and "Promotions" on matching columns
then JOIN back with "Products" to retrieve the products name
SELECT prices.ProductID,
Products.Name,
prices.Type,
prices.Price,
prices.Quantity
FROM (SELECT ID AS ProductID,
'regular' AS Type,
Price,
Quantity
FROM Products
UNION
SELECT ProductID,
Type,
Price,
Quantity
FROM Promotions ) prices
INNER JOIN Products
ON prices.ProductID = Products.ID
Check the demo here.

Left Join in MySQL View

I have two tables, one tracks purchases of products (indicated by its EAN), the other sales of the products. But not all products sold are in the purchase table and vice versa. So for example:
Purchase
PurchaseNo
EAN
1
0001
2
0002
3
0003
4
0004
Sale
SaleNo
EAN
1
0002
2
0003
3
0004
4
0005
I also have a table with the product specifications for the EAN numbers:
ProductEAN
EAN
Name
0001
Product1
0002
Product2
0003
Product3
0004
Product4
0005
Product5
I now want to create a view that tells me my current Inventory (even if the stock is negative). My current approach is to create one view for purchase and sale each where a column "Amount" tells me how many products I have bought or sold.
So for my purchases that would be:
CREATE VIEW `PurchaseAmount` AS
SELECT
`ProductEAN`.`EAN` AS `EAN`,
COUNT(`Purchase`.`EAN`) AS `Amount`
FROM (`ProductEAN` JOIN `Purchase`)
WHERE `ProductEAN`.`EAN` = `Purchase`.`EAN`
GROUP BY `ProductEAN`.`EAN`
And the equivalent for my sales.
I now want to combine these two views to create my final inventory view. The problem is that as far as I know and tested, I can only do normal joins in my Views which results in my two "sub"-views not containing the EANs that weren't purchased or sold. And consequently my final inventory view can only show the EANs that are in both the purchase and sale table.
Is there any way to do a left join in a MySQL View to just keep all EAN even if they are not used in the table the view references.
You can do it by first computing the COUNT over purchases and sales separately, then leaving the LEFT JOIN as the last operations to make the query more efficient.
SELECT ProductEAN.EAN AS EAN,
COALESCE(Purchases.num_purchases, 0) AS num_purchases,
COALESCE(Sales.num_sales, 0) AS num_sales
FROM ProductEAN
LEFT JOIN (SELECT EAN,
COUNT(EAN) AS num_purchases
FROM Purchase
GROUP BY EAN ) Purchases
ON ProductEAN.EAN = Purchases.EAN
LEFT JOIN (SELECT EAN,
COUNT(EAN) AS num_sales
FROM Sale
GROUP BY EAN ) Sales
ON ProductEAN.EAN = Sales.EAN
Hence you can take this code and store it inside a view.
Check the demo here.

MySQL - Select lowest price that has quantity, if none have quantity, select the lowest price

I have a table with product_id, warehouse, quantity, and price. My goal is to select the lowest price for each product. However, I want to choose the record with the lowest price that has a quantity, unless they are all 0 in which case I want the record with just the lowest price.
Example
product_id
warehouse
quantity
price
1
A
5
14
1
B
0
12
1
C
8
17
2
A
0
12
2
C
0
10
3
D
3
12
After the query, it should return a table such as this:
product_id
warehouse
quantity
price
1
A
5
14
2
C
0
10
3
D
3
12
My initial thought is to do some kind of inner join on price = min(price). I know how to get the record with the min price but can't wrap my brain around having it dependent on the quantity as well.

SQL task if the product has no sales in the given month, then display 0 in this month

I have to build and SQL query which must do these things:
select all products from table "products" - satisfied
SUM all sales and forecast to the next 3 months - satisfied
check if the product has no one sale, then write "0" -> here is the problem, because I don't know how to do that..
My SQL query is here..
select product.name,
(select sum(amount)
from forecast
where forecast.product_id = product.id),
sum(sale.amount)
from product join
 sale
  on sale.product_id = product.id
where sale.outlook > -4
group by product.id
Here is the products table:
id name
1 milk
2 roll
3 ham
Table sale (same structure like forecast):
product_id outlook amount
1 -1 9
1 -2 13
1 -3 14
2 -1 88
2 -3 61
3 -1 33
3 -4 16
You can use left join to bring in the rows and coalesce() to get the 0 instead of NULL:
select p.name,
(select sum(f.amount)
from forecast f
where v.product_id = p.id),
coalesce(sum(s.amount), 0)
from product p left join
sale s
on sale.product_id = product.id and
sale.outlook > -4
group by p.id
Understand the requirement to be, show the sales per product and if no sale for a product show "0". Tables are named Products and Sale.
For this, "with" statements are useful and help understanding too:
With SalesSummary as
(
select product_id, sum(amount) as ProductSales
from Sale
Group by product_id
)
select a.ProductID, ISNULL(b.ProductSales,0) as Sales
from products a left join SalesSummary b on a.product_id=b.product_id

MySQL - How to join those tables to get the correct result?

I have been trying for a couple of hours to figure this out, but it still does not work..
I have 2 tables:
Prices
Sales
The records are something like:
Prices
product_name price
--------------------
Milk 0.80
Cheese 1.00
Bread 1.50
Sales
customer_id product_name number_purchases
-------------------------------------------
15 Milk 2
15 Cheese 1
2 Butter 2
2 Candy 4
80 Bread 1
...
...
15 Bread 2
15 Milk 1
The sales are tracked per week, a customer can occur multiple times in the database with a purchase of the same goods (like in the example customer 15 buys milk twice a week, so customer 15 bought 3 packs of milk.
I want to get for a certain customer:
Each product he/she bought, with the corresponding total number of purchases of that product, and the corresponding price of the product.
This is what I have so far without errors:
SELECT product_name, SUM(number_purchases)
FROM sales S
WHERE customer_id = 80
GROUP BY product_name;
But when I want to add some lines to the code, to get the corresponding prices too, it does not work. One of the things I tried:
SELECT product_name, SUM(number_purchases), price
FROM sales S, prices P
WHERE S.product_name = P.productname
AND customer_id = 80
GROUP BY product_name;
Is this not possible in only one query or do I miss something?
Thanks a lot
Your last query is grouping by customer_id. Try changing this to product_name:
SELECT S.product_name, SUM(S.number_purchases), P.price
FROM sales S, prices P
WHERE S.product_name = P.product_name
AND S.customer_id = 80
GROUP BY S.product_name;
You should also never use commas in the from clause. Instead use explicit joins as in your first example and aggregate on price as well (or move price to the group by clause):
SELECT S.product_name, SUM(S.number_purchases), sum(P.price) total_price
FROM sales S join
prices P
ON S.product_name = P.product_name
WHERE S.customer_id = 80
GROUP BY S.product_name;
Use aliases
SELECT s.product_name, SUM(number_purchases), price
FROM sales S, prices P
WHERE S.product_name = P.productname
AND customer_id = 80
GROUP BY s.product_name;
DBMS - doesn't know wich product_name get
P.S. and I think u have to add price in group by
You query should be:
SELECT product_name, SUM(number_purchases), price
FROM sales S, prices P
WHERE S.product_name = P.productname
AND customer_id = 80
GROUP BY P.productname;