how combine innerjoin query and 2 replace query in 1 query? - mysql

I'm trying to combine 3 queries for building a search menu in opencart, but they always fail and error.
This is example query
First query:
SELECT p.product_id,
(SELECT AVG(rating) AS total
FROM review r1
WHERE r1.product_id = p.product_id
AND r1.status = '1'
GROUP BY r1.product_id) AS rating
FROM product p
LEFT JOIN product_description pd
ON (p.product_id = pd.product_id)
LEFT JOIN product_to_store p2s
ON (p.product_id = p2s.product_id)
WHERE pd.language_id = '1'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = '0'
AND ( LCASE(pd.name) LIKE '%dellxps13%'
OR MATCH(pd.tag) AGAINST('dellxps13')
)
OR LCASE(p.model) = 'dellxps13'
OR LCASE(p.sku) = 'dellxps13'
OR LCASE(p.upc) = 'dellxps13'
OR LCASE(p.ean) = 'dellxps13'
OR LCASE(p.jan) = 'dellxps13'
OR LCASE(p.isbn) = 'dellxps13'
OR LCASE(p.mpn) = 'dellxps13'
GROUP BY p.product_id
ORDER BY p.sort_order ASC, LCASE(pd.name) ASC
LIMIT 0, 15
Second query:
SELECT REPLACE (model," ","") AS 'FIND'
FROM product
WHERE REPLACE (model," ","")
It's change to p.model(for innerjoin, p.model = product.model)
Third query:
SELECT REPLACE (name," ","") AS 'FIND2'
FROM product_description
WHERE REPLACE (name," ","")
It's change to pd.name(for innerjoin, pd.name = product_description.name).
So I want replace all first, then select from replace like '%dellxps13%'
Anyone know how to combine 3 this query?
This is what I try to change and got error
AND ((LCASE(SELECT REPLACE (pd.name," ","")) FROM product_description
WHERE LCASE (REPLACE (pd.name," ",""))) LIKE '%dellxps13%'
OR MATCH(pd.tag) AGAINST('dellxps13')
)
OR LCASE((SELECT REPLACE (p.model," ","")) FROM product WHERE LCASE (REPLACE (p.model," ",""))) = 'dellxps13'
error 1064 'SELECT REPLACE (pd.name," ","")) FROM product_description
WHERE LCASE (REPLAC' at line 16.
And when I not use LCASE got error
SELECT p.product_id,
(SELECT AVG(rating) AS total
FROM review r1
WHERE r1.product_id = p.product_id
AND r1.status = '1'
GROUP BY r1.product_id) AS rating
FROM product p
LEFT JOIN product_description pd
ON (p.product_id = pd.product_id)
LEFT JOIN product_to_store p2s
ON (p.product_id = p2s.product_id)
WHERE pd.language_id = '1'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = '0'
AND ((SELECT REPLACE (pd.name," ","") FROM pd WHERE REPLACE (pd.name," ","") LIKE '%dellxps13%')
OR MATCH(pd.tag) AGAINST('dellxps13'))
OR (SELECT REPLACE (p.model," ","") FROM p WHERE REPLACE (p.model," ","") LIKE '%dellxps13%')
OR LCASE(p.sku) = 'dellxps13'
OR LCASE(p.upc) = 'dellxps13'
OR LCASE(p.ean) = 'dellxps13'
OR LCASE(p.jan) = 'dellxps13'
OR LCASE(p.isbn) = 'dellxps13'
OR LCASE(p.mpn) = 'dellxps13'
GROUP BY p.product_id
ORDER BY p.sort_order ASC, LCASE(pd.name) ASC
LIMIT 0, 15
error : 1146 - Table 'example.pd' doesn't exist

Related

How to group by product ID with latest creation date in mysql?

I have select statement as below and sample output :-
select uph.creation_date, p.name,p.product_id from product p
left join user_product_history uph on p.product_id = uph.product_id
where uph.user_id = 124 order by uph.creation_date desc
How can I group by product ID with lastest creation date? Please help. Thank you.
Edited with PHP API .model file
// ~/user/product_history
public function product_history($data) {
$sql = 'select uph.creation_date,
p.name,
p.product_id
from product p
join user_product_history uph
on p.product_id = uph.product_id and
uph.user_id = ?
join (select product_id,
MAX(creation_date) AS max_creation_date
from user_product_history
where user_id = ?
group by product_id) dt
on dt.product_id = uph.product_id and
dt.max_creation_date = uph.creation_date
order by uph.creation_date desc';
$result = $this->db->query($sql, array($data['user_id']));
$records = array();
foreach( $result->result_array() as $r ) {
$r['product_id'] = (int) $r['product_id'];
$r['sub_category_id'] = (int) $r['sub_category_id'];
$r['merchant_id'] = (int) $r['merchant_id'];
if (!isset($r['price_discount'])) $r['price_discount'] = '';
$records[] = $r;
}
return $records;
}
Firstly, you dont need a Left Join here, as you are filtering on user_product_history table also. It does seem like you want to show only those product(s), which has a creation_date corresponding to user_id = 124. So, you can simply use Inner Join instead.
In a derived table (sub-select query), determine the maximum value of creation_date for every product_id.
Now, use this result-set to join to the main tables, on product_id and the creation_date, to get the complete row.
Try the following:
select uph.creation_date,
p.name,
p.product_id
from product p
join user_product_history uph
on p.product_id = uph.product_id and
uph.user_id = 124
join (select product_id,
MAX(creation_date) AS max_creation_date
from user_product_history
where user_id = 124
group by product_id) dt
on dt.product_id = uph.product_id and
dt.max_creation_date = uph.creation_date
order by uph.creation_date desc
select
uph.creation_date,
p.name,p.product_id
from
product p
left join user_product_history uph on p.product_id = uph.product_id
where
uph.user_id = 124 and
uph.creation_date = (select
max(creation_date)
from
user_product_history)
order by
uph.creation_date desc

SQL orderby select

i have SQL query. I would like to orderby this by parent category. But i return only default category. I would like to know if i can
ORDER BY SELECT id_parent FROM cats WHERE id_category = id_default_category
Here is my query :
SELECT cp.`id_product_attribute`,
cp.`id_product`, cp.`quantity` AS cart_quantity,
cp.id_shop, pl.`name`,
p.`is_virtual`,
pl.`description_short`,
pl.`available_now`,
pl.`available_later`,
product_shop.`id_category_default`,
p.`id_supplier`,
p.`id_manufacturer`,
product_shop.`on_sale`,
product_shop.`ecotax`,
product_shop.`additional_shipping_cost`,
product_shop.`available_for_order`,
product_shop.`price`,
product_shop.`active`,
product_shop.`unity`,
product_shop.`unit_price_ratio`,
stock.`quantity` AS quantity_available,
p.`width`,
p.`height`,
p.`depth`,
stock.`out_of_stock`,
p.`weight`,
p.`date_add`,
p.`date_upd`,
IFNULL(stock.quantity, 0) as quantity,
pl.`link_rewrite`,
cl.`link_rewrite` AS category,
CONCAT(LPAD(cp.`id_product`, 10, 0),
LPAD(IFNULL(cp.`id_product_attribute`, 0), 10, 0),
IFNULL(cp.`id_address_delivery`, 0)) AS unique_id,
cp.id_address_delivery,
product_shop.advanced_stock_management,
ps.product_supplier_reference supplier_reference
FROM `ps_cart_product` cp
LEFT JOIN `ps_product` `p` ON p.`id_product` = cp.`id_product`
INNER JOIN `ps_product_shop` product_shop ON (product_shop.`id_shop` = cp.`id_shop` AND product_shop.`id_product` = p.`id_product`)
LEFT JOIN `ps_product_lang` `pl` ON p.`id_product` = pl.`id_product`
AND pl.`id_lang` = 1 AND pl.id_shop = cp.id_shop
LEFT JOIN `ps_category_lang` `cl` ON product_shop.`id_category_default` = cl.`id_category`
AND cl.`id_lang` = 1 AND cl.id_shop = cp.id_shop
LEFT JOIN `ps_product_supplier` `ps` ON ps.`id_product` = cp.`id_product` AND ps.`id_product_attribute` = cp.`id_product_attribute` AND ps.`id_supplier` = p.`id_supplier`
LEFT JOIN ps_sanishopstock_available stock
ON (stock.id_product = cp.id_product AND stock.id_product_attribute = IFNULL(`cp`.id_product_attribute, 0) AND stock.id_shop = 1 AND stock.id_shop_group = 0 )
WHERE cp.`id_cart` = 757
ORDER BY product_shop.id_category_default ASC, cp.id_product, cp.date_add ASC;
There is a lot of different table, i'm lost !
If someone have any idea.
Thanks a lot !
Yes. But like any subquery, you need parentheses:
ORDER BY (SELECT c.id_parent FROM cats c WHERE id_category = id_default_category)
I would also qualify the column names in the WHERE, but I don't know where they come from.

Slow Mysql Inner joins with multiple OR

I'm helping a friend with an e-commerce site. He has options for users to select different colours, styles, use and type of the products he's selling. The query the adds the following to the query:
INNER JOIN tbl_coloursProducts col ON ( p.product_id = col.productID AND (col.colourID = 2 OR col.colourID = 3 OR col.colourID = 5 OR col.colourID = 8 OR col.colourID = 10))
INNER JOIN tbl_useProducts tbluse ON ( p.product_id = tbluse.productID AND (tbluse.useID = 15 OR tbluse.useID = 16 OR tbluse.useID = 17 OR tbluse.useID = 18))
INNER JOIN tbl_styleProducts style ON ( p.product_id = style.productID AND (style.styleID = 39 OR style.styleID = 44))
INNER JOIN tbl_typeProducts type ON ( p.product_id = type.productID AND (type.typeID = 46 OR type.typeID = 48 OR type.typeID = 50))
The query loads fast enough when only a few options are selecting, but some users are selecting multiple or each which is causing the query to run in excess of 30 seconds and timing out.
Without altering the table structure is there a better way to optimise the query?
This is the full query:
SELECT *,
p.product_id,
Coalesce((SELECT p2sp.price
FROM ab_product_specials p2sp
WHERE p2sp.product_id = p.product_id
AND p2sp.customer_group_id = '1'
AND ( ( p2sp.date_start = '0000-00-00'
OR p2sp.date_start < Now() )
AND ( p2sp.date_end = '0000-00-00'
OR p2sp.date_end > Now() ) )
ORDER BY p2sp.priority ASC,
p2sp.price ASC
LIMIT 1), p.price) AS final_price,
pd.name AS name,
m.name AS manufacturer,
ss.name AS stock,
(SELECT Avg(r.rating)
FROM ab_reviews r
WHERE p.product_id = r.product_id
GROUP BY r.product_id) AS rating,
(SELECT Count(rw.review_id)
FROM ab_reviews rw
WHERE p.product_id = rw.product_id
GROUP BY rw.product_id) AS review
FROM ab_products p
LEFT JOIN ab_product_descriptions pd
ON ( p.product_id = pd.product_id
AND pd.language_id = '1' )
LEFT JOIN ab_products_to_stores p2s
ON ( p.product_id = p2s.product_id )
LEFT JOIN ab_manufacturers m
ON ( p.manufacturer_id = m.manufacturer_id )
LEFT JOIN ab_stock_statuses ss
ON ( p.stock_status_id = ss.stock_status_id
AND ss.language_id = '1' )
LEFT JOIN ab_products_to_categories p2c
ON ( p.product_id = p2c.product_id )
INNER JOIN tbl_coloursproducts col
ON ( p.product_id = col.productid
AND ( col.colourid = 2
OR col.colourid = 3
OR col.colourid = 5
OR col.colourid = 8
OR col.colourid = 10 ) )
INNER JOIN tbl_useproducts tbluse
ON ( p.product_id = tbluse.productid
AND ( tbluse.useid = 15
OR tbluse.useid = 16
OR tbluse.useid = 17
OR tbluse.useid = 18 ) )
INNER JOIN tbl_styleproducts style
ON ( p.product_id = style.productid
AND ( style.styleid = 39
OR style.styleid = 44 ) )
INNER JOIN tbl_typeproducts type
ON ( p.product_id = type.productid
AND ( type.typeid = 46
OR type.typeid = 48
OR type.typeid = 50 ) )
WHERE p.status = '1'
AND p.date_available <= Now()
AND p2s.store_id = 0
AND p2c.category_id = 131
GROUP BY p.product_id
ORDER BY p.product_id DESC
LIMIT 0, 8
Without the custom bits the query runs fine.
Looking at that query, not sure the ORs are the problem themselves (although you could possibly make the code more compact by using and IN clause for each one). Rather I suspect that selecting more and more options results in more rows being returned. And this is causing problems with the sub queries in the SELECT clause.
Can you try the query with the sub queries removed from the SELECT clause and see the effect that has.
You can remove the sub queries quite easily.
SELECT *,
p.product_id,
Coalesce(sub1.price, p.price) AS final_price,
pd.name AS name,
m.name AS manufacturer,
ss.name AS stock,
sub0.rating,
sub0.review
FROM ab_products p
INNER JOIN
(
SELECT r.product_id,
Avg(r.rating) AS rating,
Count(rw.review_id) AS review
FROM ab_reviews r
GROUP BY r.product_id
) sub0
ON p.product_id = sub0.product_id
LEFT OUTER JOIN
(
SELECT p2sp.product_id,
SUBSTRING_INDEX(GROUP_CONCAT(p2sp.price ORDER BY p2sp.priority ASC, p2sp.price ASC ), ',', 1) AS price
FROM ab_product_specials p2sp
WHERE p2sp.customer_group_id = '1'
AND ( p2sp.date_start = '0000-00-00' OR p2sp.date_start < NOW() )
AND ( p2sp.date_end = '0000-00-00' OR p2sp.date_end > NOW() )
GROUP BY p2sp.product_id
) sub1
ON p.product_id = sub1.product_id
LEFT JOIN ab_product_descriptions pd
ON ( p.product_id = pd.product_id
AND pd.language_id = '1' )
LEFT JOIN ab_products_to_stores p2s
ON ( p.product_id = p2s.product_id )
LEFT JOIN ab_manufacturers m
ON ( p.manufacturer_id = m.manufacturer_id )
LEFT JOIN ab_stock_statuses ss
ON ( p.stock_status_id = ss.stock_status_id
AND ss.language_id = '1' )
LEFT JOIN ab_products_to_categories p2c
ON ( p.product_id = p2c.product_id )
INNER JOIN tbl_coloursproducts col
ON ( p.product_id = col.productid
AND ( col.colourid = 2
OR col.colourid = 3
OR col.colourid = 5
OR col.colourid = 8
OR col.colourid = 10 ) )
INNER JOIN tbl_useproducts tbluse
ON ( p.product_id = tbluse.productid
AND ( tbluse.useid = 15
OR tbluse.useid = 16
OR tbluse.useid = 17
OR tbluse.useid = 18 ) )
INNER JOIN tbl_styleproducts style
ON ( p.product_id = style.productid
AND ( style.styleid = 39
OR style.styleid = 44 ) )
INNER JOIN tbl_typeproducts type
ON ( p.product_id = type.productid
AND ( type.typeid = 46
OR type.typeid = 48
OR type.typeid = 50 ) )
WHERE p.status = '1'
AND p.date_available <= Now()
AND p2s.store_id = 0
AND p2c.category_id = 131
GROUP BY p.product_id
ORDER BY p.product_id DESC
LIMIT 0, 8
As an aside, when you read from ab_product_specials you are checking for the date_start and date_end to be 0000-00-00 (ie, dates), but also comparing them with NOW() which returns a date / time field. Are those fields date or date / time fields?
My first though was to use IN to make the query eaier to read:
INNER JOIN tbl_coloursProducts col
ON p.product_id = col.productID AND col.colourID IN ( 2, 3, 5, 8, 10 )
Then I thought, I wonder if they are dynamically building SQL text to squirt into the database logic?! The optimizer is unlikely to do well at optimizing queries when they are constantly mutating in this way.
Consider a scratch table (pseudo code):
-- One time:
CREATE TABLE SratchColours ( colourID INT NOT NULL UNQIUE );
-- For each query:
DELETE FROM SratchColours;
INSERT INTO SratchColours VALUES ( 2 ), ( 3 ), ( 5 ), ( 8 ), ( 10 );
Now you dynamic list of values simply becomes just another join:
tbl_coloursProducts NATURAL JOIN SratchColours
(or you could use an inner join if you must!)
Now, having one base table for every concurrent user is probably not a great way to scale a system. Therefore, consider how to pass a bag of colourID values to the database logic (say, a stored proc), put them into a table (say, a temporary table), then join from there to your base tables.

getting fieldname from multiple tables depending on condition

I have the following mysql query:
SELECT
u.ID,
u.StudentCode,
c.classname,
s.STUDENTNAME,
u.UserCode,
g.ForeName AS MessageSentBy,
u.Message,
u.ForTchrSname AS MessageSentTo,
DATE_FORMAT(u.datetime, '%d-%m-%y') AS datesent,
u.RecordStatus
FROM
tblupdates u,
tblguardian g,
tblstudent s,
tblclass c
WHERE u.UserCode = g.GuardianCode
AND u.StudentCode = s.STUDENTCODE
AND (
YEAR(u.DateTime) = '2013'
AND MONTH(u.DateTime) = '09'
)
AND u.RecordStatus = 'N'
AND c.classcode = s.classcode
ORDER BY u.datetime DESC
Result of this query is shown below:
Now in my tblupdates for year-2013 and month-09 i have the following rows:
Now in my above result i am getting data for id=138 but i want to display all.The reason for not displaying other rows is that (usercode-30000,admin) these occur in tblteacher rather than tblguardian.So now i want that if the usercode is from tblguardian it shows guardian name but if it is from tblteacher it shows teachername but shows all the rows.Tblteacher and tblupdates can be joined by teachercode and usercode respectively.
I tried the following query but it doesnot return any row:
SELECT
u.ID,
u.StudentCode,
c.classname,
s.STUDENTNAME,
u.UserCode,
IF(
u.usercode NOT IN (g.guardiancode),
t.teachername,
g.ForeName
) AS MessageSentBy,
u.Message,
u.ForTchrSname AS MessageSentTo,
DATE_FORMAT(u.datetime, '%d-%m-%y') AS datesent,
u.RecordStatus
FROM
tblupdates u,
tblguardian g,
tblstudent s,
tblclass c,
tblteacher t
WHERE u.UserCode = g.GuardianCode
AND u.StudentCode = s.STUDENTCODE
AND t.teachercode = u.usercode
AND (
YEAR(u.DateTime) = '2013'
AND MONTH(u.DateTime) = '09'
)
AND u.RecordStatus = 'N'
AND c.classcode = s.classcode
ORDER BY u.datetime DESC
Please help me out
Try this with using CASE and i have joined you tables using LEFT join so there can be duplicates i have use GROUP BY also by u.id but bit confused for right column name please put the right column in group by
SELECT
u.ID,
u.StudentCode,
c.classname,
s.STUDENTNAME,
u.UserCode,
(CASE
WHEN u.usercode = t.teachercode THEN t.teachername
WHEN u.usercode = g.guardiancode THEN g.ForeName
ELSE END ) AS MessageSentBy,
u.Message,
u.ForTchrSname AS MessageSentTo,
DATE_FORMAT(u.datetime, '%d-%m-%y') AS datesent,
u.RecordStatus
FROM
tblupdates u
LEFT JOIN tblguardian g ON (u.UserCode = g.GuardianCode )
LEFT JOIN tblstudent s ON (u.StudentCode = s.STUDENTCODE )
LEFT JOIN tblclass c ON (c.classcode = s.classcode )
LEFT JOIN tblteacher t ON (t.teachercode = u.usercode)
WHERE u.RecordStatus = 'N'
AND (
YEAR(u.DateTime) = '2013'
AND MONTH(u.DateTime) = '09'
)
GROUP BY u.id
ORDER BY u.datetime DESC

Mysql IF statement or Case

I'm trying to get special value...
if empty p.price + ifnull = option_price_total
else special = option_price_total
.
SELECT
p.product_id,
p.price,
(SELECT ifnull(MIN(price), 'empty') AS FIELD_1 FROM etp_product_special ps WHERE ps.product_id = p.product_id AND ps.customer_group_id = '1' AND (ps.date_start = '0000-00-00' OR ps.date_start < NOW()) AND (ps.date_end = '0000-00-00' OR ps.date_end > NOW()) ORDER BY ps.priority, ps.price LIMIT 1) AS special,
///
IF special != 'empty'
Do this subquery ---v
(SELECT ifnull(MIN(price), '0.00') AS FIELD_2 FROM etp_product_option_value pov WHERE pov.product_id = p.product_id) AS option_price,
p.price + ifnull((SELECT MIN(price) AS FIELD_2 FROM etp_product_option_value pov WHERE pov.product_id = p.product_id GROUP BY p.product_id, p.price), '0.00') AS option_price_total,
/// ELSE
/// ex. special value equals 15
/// special AS option_price_total
/// Output: option_price_total = 15
(SELECT MIN(etp_product_option_value.price) AS FIELD_1 FROM etp_product_option_value WHERE etp_product_option_value.product_id = p.product_id GROUP BY etp_product_option_value.product_id) AS options,
(SELECT AVG(rating) AS total FROM etp_review r1 WHERE r1.product_id = p.product_id AND r1.`status` = '1' GROUP BY r1.product_id) AS rating
FROM
etp_product p
LEFT OUTER JOIN etp_product_description pd ON (p.product_id = pd.product_id)
LEFT OUTER JOIN etp_product_to_store p2s ON (p.product_id = p2s.product_id)
INNER JOIN etp_product_to_vendor ON (p.product_id = etp_product_to_vendor.product_id)
INNER JOIN etp_vendor ON (etp_product_to_vendor.vendor_id = etp_vendor.vendor_id)
Any idea ?