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.
Related
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.
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
I am new to SSRS. I have a requirement to display top 3 products based on sales for each country where country is a column grouping, in a tablix.So the report should look like this ( the countries should appear as columns with products and total sales underneath.Unfortunately I am unable to type the below as expected)
UK
Prod1 100
Prod3 70
Prod4 50
Spain
Prod2 80
Prod3 55
Prod4 30
Italy
Prod3 45
Prod1 20
Prod4 15
Top N filter applied at the column group does not work as it seems to be ignoring it completely. Top N cannot be applied at the Table level as it will only display Top 3 across all countries. The data is sourced from a cube.
Any help is much appreciated
This is something you should solve in your select query and that shouldn't be too hard.
I don't know your database layout so I'll try and explain it with a simple example:
Sales Table
SalesId
CustomerId
Date
Total
SalesDetails table
SalesDetailId
SalesId
Product
Quantity
CustomersTable
CustomerId
Country
Name
SELECT DISTINCT(c.Country), q.Product, q.Quantity
FROM Customers c
JOIN (SELECT c1.Country, d1.Product, SUM(d1.Quantity) as Quantity
FROM SalesDetails d1
JOIN Sales s1 ON s1.SalesId = d1.SalesId
JOIN Customer c1 ON c1.CustomerId = s1.CustomerId
GROUP BY d1.Product, c1.Country) q ON q.Country = c.Country
WHERE q.Product IN (SELECT TOP 3 d2.Product
FROM SalesDetails d2
JOIN Sales s2 ON s2.SalesId = d2.SalesId
JOIN Customer c2 ON c2.CustomerId = s2.CustomerId
WHERE c2.Country = c.Contry
GROUP BY d2.Product, c2.Country
ORDER BY SUM(d2.Quantity) DESC)
ORDER BY c.Country
I hope this is of use to you, if you share your actual database layout I'm willing to update my example based on yours.
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).
I’m new to mySQL and I’m struggling to write a query that will list all stores where a price for a product has been scanned as well as the stores where it has not been scanned. The following gives the correct result for a single product:
select distinct(s.id) as store_id, s.chainID as chain_id, p1.productID as product_id,
s.chain, s.location, s.city, prd.brand, prd.product, prd.quantity, prd.size, prd.unit
from analytics.price p1 -- Fact table with prices
join analytics.pricetime pt -- Dimension table with time a price was scanned
on p1.priceTimeID = pt.id
join analytics.product prd -- Dimension table with products
on p1.productID = prd.id
and prd.published = 1
right join analytics.store s -- Dimension table with stores and the chain they belong to
on p1.storeID = s.id
and p1.chainID = s.chainID
and p1.productID = 46720
and p1.priceTimeID between 2252 and 2265
where s.published=1
and s.chainID = 5;
When I remove the p1.productID = 46720 clause to get results for all products, I get all the stores that have scanned prices (correct), but the no price side of the right join only shows stores that have not had any prices scanned for any products. (This is a simple star schema with a price fact and dimensions of product, time and store). I would greatly appreciate help – I’ve tried this every way I can think of including “in”, “not exists” and stored procedure with cursor but I seem to hit a brick wall each way I try it.
Edited to clarify:
Here's what I'm trying to achieve:
Price table
Product Chain Store Price
100 5 1 $10
101 5 2 $20
Store table
Chain Store
5 1
5 2
5 3
Desired Result
Product Chain Store Price
100 5 1 $10
100 5 2 NULL
100 5 3 NULL
101 5 1 NULL
101 5 2 $20
101 5 3 NULL
Actual Result
Product Chain Store Price
100 5 1 $10
101 5 2 $20
NULL 5 3 NULL
I prefer the readability of using a LEFT JOIN -- this should return all published stores in chainid 5 and the associated products (given the criteria).
select distinct s.id as store_id, s.chainID as chain_id, s.chain, s.location, s.city,
prd.id as product_id, prd.brand, prd.product, prd.quantity, prd.size, prd.unit
from analytics.store s
left join analytics.price p1
on p1.storeID = s.id
and p1.chainID = s.chainID
and p1.priceTimeID between 2252 and 2265
left join analytics.product prd
on p1.productID = prd.id
and prd.published = 1
left join analytics.pricetime pt
on p1.priceTimeID = pt.id
where s.published=1
and s.chainID=5;
EDIT -- Give comments, it looks like you're looking for a Cartesian Product:
SELECT P.Product, P.Chain, S.Store, IF(P.Store=S.Store,P.Price,NULL) Price
FROM Price P, Store S
WHERE P.Chain = 5
AND S.Chain = P.Chain
ORDER BY P.Product, S.Store
SQL Fiddle Demo