how to resolve Unknown column in 'where clause'many clause - mysql

I have a problem with SQL to select same information when I hve lot of clause
the first column is unknow in other clause.
This is my sql expression:
SELECT * ,
(select sum(sell) from product_details where product_details.product_id = products.id) as total ,
(select sell from product_details where product_details.product_id = products.id order by product_details.id desc limit 1) as ysell ,
(select sum(sell) as wsell FROM (select sell from product_details where product_details.product_id = products.id order by product_details.id desc limit 2 ) as weeksell) as wsell
FROM `products`
I try to get information from product and second table is product_details
based on product ID;
ysell = last sell
total = total sell
wsell = limit 7 sell by using sum() and select from the last 7
but whene i run my expression i get error
#1054 - Unknown column 'products.id' in 'where clause'
isn't knowing in this line
(select sum(sell) as wsell FROM (select sell from product_details where product_details.product_id = products.id order by product_details.id desc limit 2 ) as weeksell) as wsell
can you suggest any ideas.

Your problem is that correlation clauses cannot be nested more than one level deep -- hence the reason by products is not seen. One solution is to transform this to conditional aggregation. That is a bit tricky, but here is one method:
SELECT p.* ,
sum(pd.sell) as total,
max(case when pd.id = pdd.max_id then pd.sell end) as ysell,
sum(case when pd.id >= pdd.id7 then pd.sell end) as wsell
FROM products p JOIN
product_details pd
ON pd.product_id = p.id JOIN
(SELECT pd.product_id, MAX(pd.id) as max_id,
SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(pd.id ORDER BY pd.id DESC), ',', 7), ',', -1) as id7
FROM product_details pd
GROUP BY pd.product_id
) pdd
ON pdd.product_id = p.id
GROUP BY p.id; -- reasonable assuming `id` is unique/primary key

Related

SQL doesn't see alias

SELECT name,
manufacturer,
prize
FROM products AS p
GROUP BY manufacturer
HAVING prize = (
SELECT Max(prize)
FROM products p1
WHERE p.`id-product` = p1.`id-product`
GROUP BY p1.manufacturer DESC
LIMIT 1
)
And the error is:
#1054 - Unknown column 'shop.p.id.product' in 'where clause'
I think you need correlated subquery instead :
SELECT p.name, p.manufacturer, p.prize
FROM products AS p
WHERE p.prize = (SELECT MAX(p1.prize) FROM products p1 WHERE p1.manufacturer = p.manufacturer);
By this way, you will get manufacturers with highest price.
EDIT : If one product has same prize then you will need PK (Primary/Identity) column that specify unique sequence :
SELECT p.name, p.manufacturer, p.prize
FROM products AS p
WHERE p.pk = (SELECT p1.pk
FROM products p1
WHERE p1.manufacturer = p.manufacturer
ORDER BY p1.prize DESC
LIMIT 1
);
If you are running with latest version of MySQL, then you can also use ranking function :
SELECT p.*
FROM (SELECT p.name, p.manufacturer, p.prize,
ROW_NUMBER() OVER (PARTITION BY p.manufacturer ORDER BY p.prize DESC) AS Seq
FROM products AS p
) p
WHERE Seq = 1;
Your query has nothing of that form. I would recommend writing the query by qualifying all column references:
SELECT p.name, p.manufacturer, p.prize
FROM products p
GROUP BY p.manufacturer
HAVING p.prize = (SELECT MAX(p1.prize)
FROM products p1
WHERE p.`id-product` = p1.`id-product`
GROUP BY p1.manufacturer DESC
LIMIT 1
);
MySQL allows the syntax with extra columns in the SELECT that are not in the GROUP BY, so that would not (normally) generate an error. It is not correct, though, by the rules of SQL.
I'm not sure what the subquery is supposed to be doing. If you want the manufacturers with the highest price, then you would not use the GROUP BY in the subquery.
If you want the highest priced product for each manufacturer:
SELECT p.name, p.manufacturer, p.prize
FROM products p
HAVING p.prize = (SELECT MAX(p1.prize)
FROM products p1
WHERE p.manufacturer = p1.manufacturer
LIMIT 1
);

Mysql count result in "where" clause

I'm facing a little problem with mysql where clause.
This is the query:
SELECT u.id user
, p.id product_purchased
, p.name product_name
, pl.store_id store
, COUNT(*) occurrences
, total_spent
, total_product_purchased
, pl.registration
FROM purchases_log pl
JOIN user u
ON pl.user_id = u.id
JOIN product p
ON pl.product_id = p.id
JOIN
( SELECT user_id
, SUM(price) total_spent
, COUNT(product_id) total_product_purchased
FROM purchases_log pl
GROUP
BY user_id
) t1
ON u.id = t1.user_id
WHERE pl.store_id IN (1,2,3)
AND occurrences > 1
GROUP
BY user
, product_name
ORDER
BY u.id ASC
, pl.registration ASC;
This is the output error:
Error Code: 1054. Unknown column 'occurrences' in 'where clause' 0.067 sec
I have already tried assign AS to occurrences or using pl.
So, can someone explain me how to correctly define the result of a count function in where clause?
You need to use HAVING instead of COUNT as group by is applied after WHERE clause and hence, it won't know about any group/aggregate columns, e.g/:
SELECT u.id user,p.id product_purchased, p.name product_name, pl.store_id store, COUNT(*) AS occurrences, total_spent, total_product_purchased, pl.registration
FROM purchases_log pl
JOIN user u ON pl.user_id=u.id
JOIN product p ON pl.product_id=p.id
JOIN (SELECT user_id, SUM(price) AS total_spent,COUNT(product_id) AS total_product_purchased FROM purchases_log pl GROUP BY user_id) t1 ON u.id=t1.user_id
WHERE pl.store_id IN (1,2,3)
GROUP BY user, product_name
HAVING COUNT(*) > 1
ORDER BY u.id ASC, pl.registration ASC;
Update
If a user has more than one product associated then it's good to add all the non aggregate columns in GROUP BY to get all the combinations of user and product. The current query will not return all the combinations.
For further optimization, as #strawberry has suggest, you can run EXPLAIN and see which indices are used and whether there is any need to create any new index.

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

SQL Query with Joins Counting multiple Results Per Record Ordering By Count

I have a table called Request.
Other tables are linked to the Request table through a request id.
There is a TwitterTweet table and a FacebookPost table.
So a single request can have 50 TwitterTweets and/or 20 FacebookPosts or any amount of Tweets/Posts
We can add them together for a total count of 70.
I'm trying to create a query that could tell me what is the request with the highest total count.
I know this is wrong:
(I attempted to just order them by the counts within the TwitterTweet, but it would not let me do an OUTER JOIN which I thought
would bring back the Count.count column. It forced me to do a Left Join for it to compile. My Logic was to do a join so
that the results were calculated for each row by the requestid)
SELECT r1.`id` AS requestid, r1 . *
FROM `Request` AS r1
LEFT JOIN
(SELECT COUNT( * ) AS count, rid
FROM
((SELECT `TwitterTweet`.`id` AS `smid` , `TwitterTweet`.`requestid` AS rid
FROM `TwitterTweet`
WHERE `TwitterTweet`.`requestid` = requestid
AND `TwitterTweet`.`active` =1) AS talias
)) AS Count ON ( Count.rid = requestid )
ORDER BY Count.count
*When I tried to add in the Facebook side it would not compile any more
(The concept is that the results are added from TwitterTweet with the results from FacebookPost
that are attached to the specific requestid which would give us a count. The entire result
set should be ordered by that count)
SELECT r1.`id` AS requestid, r1 . *
FROM `Request` AS r1
LEFT JOIN
(SELECT COUNT( * ) AS count, rid
FROM
((SELECT `TwitterTweet`.`id` AS `smid` , `TwitterTweet`.`requestid` AS rid
FROM `TwitterTweet`
WHERE `TwitterTweet`.`requestid` = requestid
AND `TwitterTweet`.`active` =1 ) AS talias
UNION All
(SELECT `FacebookPost`.`id` AS `smid`, `FacebookPost`.`requestid` AS rid
FROM `FacebookPost`
WHERE `FacebookPost`.`requestid` = requestid
AND `FacebookPost`.`active` = 1) as falias
)) AS Count ON ( Count.rid = requestid )
ORDER BY Count.count
I updated the Query with an attempt to add an alias:
SELECT rid, SUM(count) total_count
FROM
(
(SELECT COUNT(*) AS count, r.rid
FROM request r
JOIN TwitterTweet tt
ON r.id = tt.requestid
WHERE tt.active = 1
GROUP BY r.rid) AS twitter
UNION ALL
(SELECT COUNT(*) AS count, r.rid
FROM request r
JOIN FacebookPost fp
ON r.id = fp.requestid
WHERE fp.active = 1
GROUP BY r.rid ) AS fbook
)
GROUP BY rid
ORDER BY SUM(count) DESC
I made another adjustment to give the middle subquery an alias, but now I only get one row returned with a zero in the rid column and 5686 in the total_count column...the 5686 might be all of the results.
SELECT counts.rid, SUM(count) total_count
FROM
(
SELECT COUNT(*) AS count, r.requestid AS rid
FROM request r
JOIN TwitterTweet tt
ON r.id = tt.requestid
WHERE tt.active = 1
GROUP BY r.requestid
UNION ALL
SELECT COUNT(*) AS count, r.requestid AS rid
FROM request r
JOIN FacebookPost fp
ON r.id = fp.requestid
WHERE fp.active = 1
GROUP BY r.requestid
) AS counts
GROUP BY counts.rid
ORDER BY SUM(count) DESC
Got it!!!
Thanks for your help guys, I had to remove those joins on the request:
SELECT counts.rid, SUM(count) total_count
FROM
(
SELECT COUNT(*) AS count, tt.requestid AS rid
FROM TwitterTweet tt
WHERE tt.active = 1
GROUP BY tt.requestid
UNION ALL
SELECT COUNT(*) AS count, fp.requestid AS rid
FROM FacebookPost fp
WHERE fp.active = 1
GROUP BY fp.requestid
) AS counts
GROUP BY counts.rid
ORDER BY SUM(count) DESC
SELECT id, SUM(count) total_count
FROM
(
SELECT COUNT(*) AS count, r.id
FROM request r
JOIN TwitterTweet tt
ON r.id = tt.requestid
WHERE tt.active = 1
GROUP BY r.id
UNION ALL
SELECT COUNT(*) AS count, r.id
FROM request r
JOIN FacebookPost fp
ON r.id = fp.requestid
WHERE fp.active = 1
GROUP BY r.id
) sub
GROUP BY id
ORDER BY SUM(count) DESC
;

Optimize MySQL Query

I have two tables 1.category 2. product tables.I want total products under a category,total sub-products under a category with author who last created the product or sub-product under product along with create date.
My Query is working like below:
SELECT c.category_id,c.title,c.type,c.alias,
(SELECT COUNT(product_id)
FROM products
WHERE parent_type='main'
AND category_id=c.category_id
AND is_active=1
) as total_main_products,
(SELECT count(product_id)
FROM products
WHERE parent_type IN('subtypeL1','subtypeL2','subtypeL3')
AND category_id=c.category_id
AND is_active=1
) as total_sub_products,
DATE_FORMAT(
(SELECT FROM_UNIXTIME(created) as update_time
FROM products
WHERE parent_type='main'
AND category_id=c.category_id
ORDER BY update_time desc limit 1
),'%b %d,%Y at %r'
)as last_updated,
(SELECT user_id
FROM products
WHERE parent_type='main'
AND category_id= c.category_id
ORDER BY created desc limit 1
) as updated_by
FROM category c
WHERE c.type=1
AND c.is_active=1
ORDER BY c.created DESC
Looking for a discussion , Is this the right & efficient way to write query or we have any other way to get the same result.I tried JOIN options but not returning the correct result.
Any help or suggestion would be greatly appriciated.
Thanks
Something like this (without last updated_by field) -
SELECT c.category_id, c.title, c.type, c.alias,
COUNT(IF(p.parent_type='main' AND p.is_active = 1, p.product_id, 0)) total_main_products,
COUNT(IF((p.parent_type='subtypeL1' OR p.parent_type='subtypeL2' OR p.parent_type='subtypeL3') AND p.is_active = 1, p.product_id, 0)) total_sub_products,
FROM_UNIXTIME(MAX(IF(p.parent_type='main', update_time, 0))) last_updated -- add formatting here
FROM category c
LEFT JOIN products p
ON p.category_id = c.category_id
WHERE
c.type = 1 AND c.is_active = 1
GROUP BY
p.category_id
ORDER BY
c.created DESC