select sum qty from 2 tables - mysql

In MySQL I have 4 tables:
- product(id)
- order(id)
- order_detail_1(id, product_id, order_id, qty)
- order_detail_2(id, product_id, order_id, qty)
I want to get the sum of the quantity of products sold from the 2 tables (order_detail_1, order_detail_2) grouping them by product
produt can existe in order_detail_1 and not in order_detail_2 and vice versa
i tested this query and it worked but I want a simpler query without the union and the subquery.
select tmp.product_id ,sum(tmp.qty) from
(
(
select order_detail_1.product_id ,sum(order_detail_1.qty)
from order_detail_1
inner join order on order_detail_1.id_order = order.id
where order_detail_1.product_id is not null
group by order_detail_1.product_id
)
union all
(
select order_detail_2.product_id ,sum(order_detail_2.qty)
from order_detail_2
inner join order on order_detail_2.id_order = order.id
where order_detail_2.product_id is not null
group by order_detail_2.product_id
)
) tmp
group by tmp.product_id

It looks like you're not using order table other then checking if it exists, so you can use EXISTS()
SELECT p.product_id,sum(p.qty) as qty
FROM (SELECT product_id,qty,id_order FROM order_detail_1
WHERE product_id IS NOT NULL
UNION ALL
SELECT product_id,qty,id_order FROM order_detail_2
WHERE product_id IS NOT NULL) p
WHERE EXISTS(SELECT 1 FROM order o
WHERE o.id = p.id_order)
GROUP BY p.product_id

If a product is in only one table, you can use left join:
select p.id, (coalesce(sum(od1.qty), 0) + coalesce(sum(od2.qty, 0))) as qty
from product p left join
order_detail_1 od1
on od1.product_id = p.id left join
order_detail_2 od2
on od2.product_id = p.id
group by p.id;
This formulation depends on the fact that the two tables are exclusion -- a product is in only one table.
EDIT:
If products can exist in both tables, then you need to aggregate them first:
select p.id, (coalesce(od1.qty, 0) + coalesce(od2.qty, 0)) as qty
from product p left join
(select product_id, sum(qty) as qty
from order_detail_1 od1
group by product_id
) od1
on od1.product_id = p.id left join
(select product_id, sum(qty) as qty
from order_detail_2 od2
group by product_id
) od2
on od2.product_id = p.id;

Related

SQL Product Categories with Product Count and Parent-Categories

I am trying to write a SQL query to fetch:
Category_ID, Category_Name, Category_Parent, Category, ProductCount
from two tables Product_Category and Product
Product_Category has columns: id, name, parent_id, status
Product has columns: id, category_id, name
I want to get the result from the query:
Category_ID | Category_Name | Category_Parent | ProductCount
Using over you can do the same group by work in aggregate functions.
SELECT
DISTINCT Product_Category.id AS Category_ID,
Product_Category.name AS Category_Name,
Product_Category.parent_id AS Category_Parent,
COUNT(Product.id) OVER (partition BY Product_Category.id) AS ProductCount
FROM Product JOIN Product_Category ON Product.category_id = Product_Category.id
result in mysql : https://dbfiddle.uk
So, I found the solution to the problem.
SELECT
X.id,
X.category,
X.parent,
X.status,
Y.product_count
FROM
(
SELECT
c.id AS id,
c.name AS Category,
p.name AS Parent,
c.status AS
STATUS
FROM
product_category c
LEFT JOIN product_category p ON
c.parent_id = p.id
) X
LEFT JOIN(
SELECT
c.id,
COUNT(p.id) AS product_count
FROM
product_category c
LEFT JOIN product p ON
c.id = p.category_id
GROUP BY
p.category_id
) AS Y
ON
X.id = Y.id

Optimize query with multiple subquery joins

I have a query that gets the product description from product table (1st select) then subtracts it to the following subquery statements to get the no. of stocks remaining:
-sum of each product bought in the inventory table (2nd)
-sum of each product sold in the sales_detail table (3rd)
-sum of each product transferred to another branch in the stock_transfer table (4th)
-sum of each product that got damaged in the damaged_product table (5th)
The problem is every time this query loads, it goes full search of all 4 tables to get the sum of the quantity columns. And as time goes by, more records are stored and the query will become slower. Any suggestions?
SELECT p.Id,p.Product_Name Product,p.Description, c.Category_Name Category,sc.Subcategory_Name Subcategory,s.Supplier_Name Supplier, p.Selling_Price `Unit Price`,i.Stocks,s.Sales, i.Stocks - IFNULL(s.Sales, 0) - IFNULL(t.Transfer, 0) - IFNULL(d.Damage, 0) AS Remaining
FROM (SELECT Id, Product_Name, Description, Selling_Price, Category_Id, Subcategory_Id, Supplier_Id FROM product WHERE enable_flag = 1) p
LEFT OUTER JOIN(SELECT product_id, COALESCE(SUM(quantity), 0) AS Stocks
FROM inventory
WHERE enable_flag = 1 GROUP BY product_id) i ON p.Id = i.product_id
LEFT OUTER JOIN(SELECT product_id, COALESCE(SUM(quantity), 0) AS Sales
FROM sales_detail
WHERE enable_flag = 1 GROUP BY product_id) s USING(product_id)
LEFT OUTER JOIN(SELECT product_id, COALESCE(SUM(transfer_quantity), 0) AS Transfer
FROM stock_transfer
WHERE enable_flag = 1 GROUP BY product_id) t USING(product_id)
LEFT OUTER JOIN(SELECT product_id, COALESCE(SUM(damaged_quantity), 0) AS Damage
FROM damaged_product
WHERE enable_flag = 1 GROUP BY product_id) d USING(product_id)
JOIN Category c ON p.Category_Id=c.Id
JOIN Subcategory sc ON p.Subcategory_Id=sc.Id
JOIN Supplier s ON p.Supplier_Id=s.Id;
The use of subqueries prevents the use of indexes, which can slow down a query. I would suggest a query such as this:
SELECT p.*, sc.Subcategory_Name as Subcategory, s.Supplier_Name as Supplier,
p.Selling_Price as `Unit Price`,
(SELECT COALESCE(SUM(quantity), 0)
FROM inventory i
WHERE s.enable_flag = 1 AND s.product_id = p.product_id
) as stocks,
(SELECT COALESCE(SUM(quantity), 0)
FROM sales_detail sd
WHERE i.enable_flag = 1 AND i.product_id = p.product_id
) as sales,
(SELECT COALESCE(SUM(tansferquantity), 0)
FROM stock_transfer st
WHERE st.enable_flag = 1 AND st.product_id = p.product_id
) as transfers,
(SELECT COALESCE(SUM(damaged_quantity), 0)
FROM damage d
WHERE d.enable_flag = 1 AND d.product_id = p.product_id
) as damaged
FROM product p JOIN
Category c
ON p.Category_Id = c.Id JOIN
Subcategory sc
ON p.Subcategory_Id = sc.Id JOIN
Supplier s
ON p.Supplier_Id = s.Id
WHERE p.enable_flag = 1;
For performance, the underlying tables want indexes on (product_id, enable_flag, quantity). MySQL can use the index for aggregation in a correlated subquery.
I realize that you also have calculated values. You may need to do these calculations in an outer query, taking the hit of an additional materialization of the subquery.

Select from 3 tables with two order by before two group by

I try to get a list of products with each newest and lowest offer price
Table product:
id | name
Table offer:
id | product_id | price | created | dealer_id
Table invalids:
id | offer_id | status
I have tried:
SELECT * FROM product INNER JOIN
(
SELECT offer.product_id , offer.price
FROM offer
LEFT JOIN invalids
ON offer.id = invalids.offer_id
WHERE invalids.id IS NULL
GROUP BY offer.dealer_id
ORDER BY offer.created DESC
) o
ON o.product_id = product.id
ORDER BY product.name
I have tried an sqlfiddle http://sqlfiddle.com/#!9/32658/3 with this offer values:
(`id`, `price`, `dealer_id`, `product_id`, `created`)
(1,12.60,1,1,'2015-05-17 08:44:45'),
(2,13.00,1,1,'2015-08-17 08:44:45'),
(3,20.00,1,1,'2015-08-17 08:45:30'),
(4,10.00,1,1,'2015-08-17 08:45:46'),
(5,4.00,2,1,'2015-05-17 08:44:11'),
(6,11.00,2,1,'2015-08-17 08:44:46'),
(7,5.00,2,1,'2015-08-17 08:45:31'),
(9,110.00,2,2,'2015-08-17 08:46:58'),
(10,11.00,2,2,'2015-08-17 08:47:12');
Expected value for product ID 1 is offer ID 7 with price 5.
These steps I think I must realize:
Order offers by created and group by dealer_id to get newest entries
Take result from step 1 and order it by price to get smallest price.
Make this for all products
Maybe I must use a second SELECT FROM offer with GROUP BY and ORDER BY but how do I get I the product_id from the first (outer) select?
Well I would start by getting the latest date for each product offer like this:
SELECT product_id, MAX(created) AS latestOffer
FROM offer
GROUP BY product_id;
Once you have that, you can join it to the original table to get that offer:
SELECT o.*
FROM offer o
JOIN(
SELECT product_id, MAX(created) AS latestOffer
FROM offer
GROUP BY product_id) tmp ON tmp.product_id = o.product_id AND tmp.latestOffer = o.created;
Here is an SQL Fiddle example.
This query should help you:
SELECT *
FROM product
JOIN (
SELECT product_id, min(price) as minPrice, max(created) as newestOffer
FROM offer
WHERE id NOT IN (SELECT offer_id FROM invalids)
GROUP BY 1
) as b
ON product.id = b.product_id
A shot in the dark based on what I understand you to be after...
lots of nested subqueries.. keep thinking there's got to be a better way...
SELECT OO.ID, OO.Price, OO.Dealer_Id, OO.Product_ID, OO.created, P.name
FROM Offer OO
INNER JOIN (
SELECT Min(Price) as MinP
FROM offer O
INNER JOIN (
SELECT max(OI.created) as LatestOffer, OI.Dealer_ID, OI.Product_ID
FROM Offer OI
LEFT JOIN invalids I
on OI.Id = I.offer_Id
WHERE I.ID is null
GROUP BY OI.Dealer_Id, OI.Product_Id
) B
on O.Dealer_Id = B.Dealer_Id
and O.Product_Id = B.Product_Id
and O.Created = B.LatestOffer
) Z
on OO.Price = Z.MinP
INNER JOIN product P
on P.ID = OO.Product_ID
SQL FIDDLE

Re-arrange a MySQL nested query

How can i redo the following query to use only JOINs instead of the nested query?
SELECT SUM(allqty) AS allqty
,COUNT(*) AS orders
FROM (SELECT SUM(S.Qty) AS allqty
FROM data_intra.yw1_ordersheet S
INNER JOIN data_intra.productdata P ON P.productid=S.productid
WHERE P.eCode LIKE (SELECT eCode
FROM data_intra.productdata
WHERE productid=1001)
GROUP BY S.OrderPO) as A;
Here are 2 guesses. Both use IN() instead of LIKE()
This will produce one row for each S.OrderPO
SELECT
SUM(S.Qty) AS allqty
, S.OrderPO
FROM data_intra.yw1_ordersheet S
INNER JOIN data_intra.productdata P
ON P.productid = S.productid
WHERE P.eCode IN (
SELECT
eCode
FROM data_intra.productdata
WHERE productid = 1001
)
GROUP BY
S.OrderPO
;
This will produce one row, counting the distinct number of S.OrderPO
SELECT
SUM(S.Qty) AS allqty
, COUNT(DISTINCT S.OrderPO) AS orders
FROM data_intra.yw1_ordersheet S
INNER JOIN data_intra.productdata P
ON P.productid = S.productid
WHERE P.eCode IN (
SELECT
eCode
FROM data_intra.productdata
WHERE productid = 1001
)
;

MySQL Query to fetch data from multiple tables

I have following tables
1) Products (productid, name, description, price)
2) Sales (salesid, productid, buyername, buyeremail, status)
3) ProductViews (viewid, productid)
Now, I need a query that can output as
ProductID ProductName Price TotalViews TotalSales
Help appreciated, thanks.
SELECT p.productid, p.name, p.price, COUNT(pv.viewid) AS totalviews, COUNT(s.salesid) AS totalsales
FROM Products p
LEFT JOIN Sales s ON s.productid = p.productid
LEFT JOIN ProductViews pv ON pv.productid = p.productid
GROUP BY p.productid, p.name, p.price
Extended group by for completeness sake but it could just be p.productid.
You can use subqueries to get the count of views and sales:
SELECT
a.productid,
a.name,
a.price,
(SELECT COUNT(b.viewid)
FROM ProductViews b
WHERE b.productid = a.productid) as TotalViews,
(SELECT COUNT(c.salesid)
FROM Sales c
WHERE c.productid = a.productid) as TotalSales
FROM
Products a
Select p.ProductID, p.ProductName, p.Price, s.c as TotalSales, v.c as TotalViews
FROM Products p
INNER JOIN (select productid, count(*) as c from Sales group by productid) s
ON s.productId = p.productid
INNER JOIN (select productid, count(*) as c from ProductViews group by productid) v
ON p.productId = v.productid
If you have a product that doesn't have a sale or a view you will need to left join instead
SELECT a.productid, a.name, a.price, (
SELECT COUNT( b.viewid )
FROM ProductViews b
WHERE b.productid = a.productid
) AS TotalViews, (
SELECT COUNT( c.salesid )
FROM Sales c
WHERE c.productid = a.productid
) AS TotalSales
FROM products a