Sql query using joins to find sum of quantity - mysql

Here,in billtran table the productid=1 is repeated twice
I want to find the sum(billtran.quantity) of each productid separately
select Query1:
select name,billtran.quantity from product inner join billtran on product.id=billtran.productid where product.id in(select id from product)

Per comment:
select name, SUM(billtran.quantity) from product inner join billtran on product.id=billtran.productid where product.id in(select id from product)
GROUP BY NAME
My additions in caps
Note: where product.id in(select id from product) is an entirely useless where clause and should be removed. Queries don't have to have a where clause and don't need one that says a table id should be in all the ids in that table (always true)
I would hence have written this one as:
SELECT
p.name,
SUM(b.quantity) as sumof_quantity
FROM
product p
INNER JOIN billtran b ON p.id=b.productid
GROUP BY
p.name

Very simple query. Pls check below:
select product.name,sum(billtran.quantity) from product inner join billtran on product.id=billtran.productid group by billtran.productid

First of all you have to get the sum of the quantity according to the product_id
SELECT product.name, SUM(billtran.quantity) AS value_sum
FROM billtran inner join product on product.id= billtran.product_id where product.id in(select id from product )
GROUP BY product_id;
This will be the result:
name quantity
abc 6
xyz 1
pqt 3
You can get the same result by grouping the product.name as well:
SELECT product.name, SUM(billtran.quantity) AS value_sum
FROM billtran inner join product on product.id=billtran.product_id where product.id in(select id from product)
GROUP BY product.name;

Related

How to reduce query time of the sql statement,mysql

Here is the sql(mysql):
Table product and product_sale_app
it will pass in two parameters,appkey is the attribute of table product_sale_app;category is the attribute of table product.I need get effect_date,product_id,name from table product and use the above conditions.
SELECT effect_date,
product_id,
name
FROM product
WHERE product_id IN
(SELECT product_id
FROM product_sale_app
WHERE appkey =88888
AND product_id IN
(SELECT product_id
FROM product
WHERE category =1 ) )
Instead of sub queries, JOIN the tables using product_id and then put conditions inside the WHERE clause.
Try the following:
SELECT p.effect_date,
p.product_id,
p.name
FROM product AS p
JOIN product_sale_app AS psa ON psa.product_id = p.product_id
WHERE p.category = 1 AND psa.appkey = 88888

Get cheapest price for a product

I have two tables: products and prices
products
id (PK)
name
prices
id (PK)
product_id (FK > products)
price
originalPrice
Each product might have multiple prices. What I want to achieve is a query that returns me all products on-sale with its cheapest price.
on-sale = price < originalPrice
if a product is not on-sale, it should not be included in the results
if a product has multiple prices that qualify for on-sale, only return the cheapest price.
The resulting table should have these columns
products.id
products.name
prices.id
prices.price
prices.originalPrice
With my attempts I'm ending up with this issue: #1055 - Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'tbl.price' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by. Please note that I cannot change the config.
MySQL version: 5.7.22
I have uploaded a SQL export with sample data here: https://www.dropbox.com/s/6ucdv6592dum6n6/stackoverflow_export.sql?dl=0
select pro.name, MIN(pri.price) from products pro
inner join price pri on pri.product_id = pro.id
where pri.price < pri.originalPrice
group by pro.name
heres a shot without any data :p may need a little tweaking
Try this:
SELECT *
FROM `products` pro
JOIN price pri on pri.productId = pro.id
WHERE pri.price < pri.originalPrice
AND pri.price =
(
SELECT min(p.price)
FROM price p
WHERE p.productId = pro.id AND p.price < p.originalPrice
)
Hope this works for you
SELECT *,MIN(price) FROM (
SELECT name, products.id,price
FROM products
INNER JOIN productItems
ON products.id = productItems.productId
WHERE price < originalPrice
ORDER BY (price-originalPrice)
) as tbl GROUP BY id;
OR
SELECT *,MIN(diff) FROM (
SELECT name, products.id,price,(price-originalPrice) as "diff"
FROM products
INNER JOIN productItems
ON products.id = productItems.productId
WHERE price < originalPrice
ORDER BY products.id,(price-originalPrice)
) as tbl GROUP BY id;
This works with that dropbox link you gave: http://sqlfiddle.com/#!9/a6306d/3
select pro.name, MIN(pri.price) from products pro
inner join price pri on pri.productId = pro.id
where pri.price < pri.originalPrice
group by pro.name

SQL JOIN: Select Records from Another Table With Matching IDs

I am having trouble building a correct SQL JOIN statement to select some records from another table.
--Table Product:
ID
Name
CatID1
CatID2
and
--Table Category:
CatID
CategoryName
Product.CatID1, Product.CatID2 are referenced to Category.CatID
So I really want to select Product fields and replace Product.CatID1, Product.CatID2 with Category.CategoryName (for Product.CatID1) and Category.CategoryName (for Product.CatID2).
This obviously does not work but explains what I need:
SELECT Product.ID, Product.Name,
Category.CategoryName as Product.CatID1,
Category.CategoryName as Product.CatID2
from product, categories;
All you need is a double LEFT JOIN to categories table:
SELECT p.ID, p.Name,
c1.CategoryName as CatID1,
c2.CategoryName as CatID2
from product AS p
LEFT JOIN categories AS c1 ON p.CatID1 = c1.CatID
LEFT JOIN categories AS c2 ON p.CatID2 = c2.CatID
If there is no match for either CatID1 or CatID2, the corresponding field in the SELECT clause is going to be NULL.
SELECT Product.ID,
Product.Name,
C1.CategoryName as Product.CatID1,
C2.CategoryName as Product.CatID2
FROM Product JOIN Category C1 ON C1.CatID = CatID1
JOIN Category C2 ON C2.CatID = CatID2 ;
Use the category table twice.
What if you decide, in the future, that a product can be in 3 categories? Really, you should have a joining table for these and remove the repeating info from Product.

Pull data from 3 tables

I have 3 tables as follows :
Table 1: Product
id_product [Primary Key],added_time.
Table 2: Category
id_category [Primary Key],Category_name.
Table 3: product_category
id_category,id_product [Both Foreign Keys]
I want to pull Data as
Category_name,No Of Products in this Category,Last time when product was added to Category(Latest product added_time).
You could use this SQL:
SELECT Category.Category_name,
Count(DISTINCT Product.id_product) AS num_products,
Max(Product.added_time) last_added_time
FROM Category
LEFT JOIN product_category
ON product_category.id_category = Category.id_category
LEFT JOIN Product
ON Product.id_product = product_category.id_product
GROUP BY Category.Category_name;
Note that by using LEFT JOIN you will be certain to list all categories even those for which no products exist. If you don't want those, replace both LEFT keywords with INNER.
Note also that in standard SQL you need to GROUP BY any columns you mention in the SELECT list, unless they are aggregated, like with MAX or COUNT.
SELECT C.`Category_name`,
(SUM(IF(P.`id_product`IS NULL,0,1))) AS No_of_Products,
MAX(P.`added_time`) AS Latest_time
FROM
Category C
LEFT JOIN
product_category P_C ON C.`id_category` = P_C.`id_category`
LEFT JOIN
Product P ON P.`id_product` = P_C.`id_product`
GROUP BY C.`id_category`
Hope this helps.

WHERE value IS NOT IN (subquery)

I've been struggling with this query.
I have two tables. One with coupons and Invoicenumbers. One with Invoicenumbers and customer names.
I need to get the customers who have not used a given coupon.
Here are the tables:
Promotion table:
Promotions
Invoice | Coupon
----------------
1 | couponA
2 | couponB
3 | couponB
Orders Table:
Orders
Invoice | Customer
------------------
1 | Jack
2 | Jack
3 | Jill
So Jack has used coupons A and B. And Jill has only used coupon B.
If my query were select customers who have not used coupon A, I should get Jill.
This works, but it seems clumsy and slow. Is there a better way?
SELECT Customer
FROM Promotions INNER JOIN Orders
ON Promotions.Invoice = Orders.Invoice
WHERE Customer NOT IN(
SELECT Customer
FROM Promotions INNER JOIN Orders
ON Promotions.Invoice = Orders.Invoice
WHERE Coupon = couponA)
GROUP BY Customer
Thanks for looking!
edit:
Here's an SQLFiddle schema
http://sqlfiddle.com/#!2/21d31/6
Updated: We should use prefer to use joins for better performance when its easy to do for us. Join vs. sub-query
Sql Fiddle
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders o2
join
(
Select distinct invoice from Promotions where Coupon='couponA'
) t3
on o2.invoice = t3.invoice
) t2
on o.customer != t2.changedname;
Note: I changed column name customer for t3 because two joined tables must have different column names
Explanation:
Using inner or sub query is expensive when you have big data. use joins instead, lets learn converting subquery to join
With Subquery We had:
Select distinct Customer from orders where customer not in
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));
Converting sub-query to join
First step:
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA')
) t2
on o.customer != t2.changedname;
2nd step:
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders o2 where invoice
join
(
Select distinct invoice from Promotions where Coupon='couponA'
) t3
on o2.invoice = t3.invoice
) t2
on o.customer != t2.changedname;
And that's it, much faster for tables having numerous rows
Original answer:
Use not in. Have a look.
Select distinct Customer from orders where customer not in
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));
Edit I have added distinct to make query faster
SQL Fiddle
SELECT DISTINCT o2.customer FROM ORDER o2
LEFT JOIN (promotions p1
JOIN Orders o1 ON p1.cuopon = 'CuoponA' AND p1.invoice = o1.invoice ) p3
ON o2.customer = p3.customer
WHERE p3.customer IS NULL
Try this query instead:
SELECT DISTINCT Customer
FROM Orders o1
WHERE NOT EXISTS (
SELECT 1
FROM Orders o2
INNER JOIN Promotions ON Promotions.Invoice = o2.Invoice
WHERE o1.Customer = o2.Customer AND Coupon = 'couponB')
The idea is to get rid of the GROUP BY by removing a join in the top part of the query, and also eliminate the NOT IN by making a coordinated subquery.
Here is a link to sqlfiddle.
Try this with a right join
SELECT Customer, Coupon
FROM Promotions
RIGHT JOIN Orders ON Promotions.Invoice = Orders.Invoice
AND Coupon = 'couponA'
GROUP BY Customer
HAVING Coupon IS NULL