SELECT COUNT(DISTINCT `product_id`) AS `total`
FROM(
SELECT DISTINCT `p`.`product_id`
FROM oc_category_path cp
LEFT JOIN oc_product_to_category p2c ON (cp.category_id = p2c.category_id)
LEFT JOIN oc_product_filter pf ON (p2c.product_id = pf.product_id)
LEFT JOIN oc_product p ON (pf.product_id = p.product_id)
LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id)
LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id)
INNER JOIN `oc_product_filter` AS `pf` ON `p2c`.`product_id` = `pf`.`product_id`
WHERE IF( `p`.`quantity` > 0, 7, `p`.`stock_status_id` ) IN(7)
AND `p`.`date_available` <= NOW()
AND `p`.`status` = '1'
AND `cp`.`path_id` = '452'
AND `pf`.`filter_id` IN(241)
AND pd.language_id = '1'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = '0'
AND cp.path_id = '452'
AND pf.filter_id IN (241)
) AS `tmp`
This line...
LEFT JOIN oc_product_filter pf ON (p2c.product_id = pf.product_id)
... shares a table alias with this line ...
INNER JOIN `oc_product_filter` AS `pf` ON `p2c`.`product_id` = `pf`.`product_id`
That can't happen. So give the second one a different alias...
SELECT COUNT(DISTINCT product_id) total
FROM
( SELECT DISTINCT p.product_id
FROM oc_category_path cp
LEFT
JOIN oc_product_to_category p2c
ON p2c.category_id = cp.category_id
JOIN oc_product_filter pf
ON pf.product_id = p2c.product_id
JOIN oc_product p
ON p.product_id = pf.product_id
JOIN oc_product_description pd
ON pd.product_id = p.product_id
JOIN oc_product_to_store p2s
ON p2s.product_id = p.product_id
JOIN oc_product_filter pf2 -- <-- changed
ON pf.product_id = p2c.product_id
WHERE IF(p.quantity > 0, 7, p.stock_status_id ) IN(7)
AND p.date_available <= NOW()
AND p.status = 1
AND cp.path_id = 452
AND pf.filter_id IN(241)
AND pd.language_id = 1
AND p.status = 1
AND p.date_available <= NOW()
AND p2s.store_id = 0
AND cp.path_id = 452
AND pf2.filter_id IN(241) -- <-- changed
) tmp;
Related
I want to export all products from an Open Cart database with their parent categories.
My tables are:
oc_product_description (product_id, name, language ....)
oc_product (product_id, model, price, status ...)
oc_product_to_category (product_id, category_id)
oc_category (category_id, status ....)
oc_category_description (category_id, name, language_id ...)
Here is my code so far:
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
join oc_category c on pc.category_id = c.category_id
join oc_category_description cd on c.category_id = cd.category_id
join oc_category c2 on (c.parent_id = c2.category_id)
join oc_category_description cd2 on c.category_id = cd2.category_id
join oc_category c3 on (c2.parent_id = c3.category_id)
join oc_category_description cd3 on c3.category_id = cd3.category_id
where
p.status = 1 AND pd.language_id = 2 AND c.status = 1 AND cd.language_id = 2
AND ((c2.status = 1 AND cd2.language_id = 2) OR c.parent_id = 0)
AND ((c3.status = 1 AND cd3.language_id = 2) OR c2.parent_id = 0)
But the problem is that it doesn't return products with only one or two level categories (c.parent_id = 0 and/or c2.parent_id = 0)
UPDATE
I ended up exporting 3 different files and then merge them... 1st file with all 3 level of categories, 2nd file with 2 level of categories and 3rd file with only one level of category
what's making it null is your 3rd level category. Add condition to your 3rd level category when joining.
join oc_category c3 on (c2.parent_id = c3.category_id and c3.category_id != c.category_id)
complete query
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
join oc_category c on pc.category_id = c.category_id
join oc_category_description cd on c.category_id = cd.category_id
join oc_category c2 on (c.parent_id = c2.category_id and c2.category_id != c.category_id)
join oc_category_description cd2 on c.category_id = cd2.category_id
join oc_category c3 on (c2.parent_id = c3.category_id and c2.category_id != c.category_id and c3.category_id != c.category_id)
join oc_category_description cd3 on c3.category_id = cd3.category_id
where p.status = 1 AND pd.language_id = 2 AND c.status = 1 AND cd.language_id = 2 AND
((c2.status = 1 AND cd2.language_id = 2) OR c.parent_id IS NULL)
AND ((c3.status = 1 AND cd3.language_id = 2) OR c2.parent_id IS NULL)
Please use left join instead of join I guess
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
LEFT join oc_category c on pc.category_id = c.category_id
LEFT join oc_category_description cd on c.category_id = cd.category_id
LEFT join oc_category c2 on (c.parent_id = c2.category_id)
LEFT join oc_category_description cd2 on c.category_id = cd2.category_id
LEFT join oc_category c3 on (c2.parent_id = c3.category_id)
LEFT join oc_category_description cd3 on c3.category_id = cd3.category_id
where
p.status = 1
Code beforehand have a little bug:
'cat 2' cd2 have same name with 'cat 1' cd
because in 8 line forgot 2 after first c
betters write c2.category_id = cd2.category_id
complete query
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
LEFT join oc_category c on pc.category_id = c.category_id
LEFT join oc_category_description cd on c.category_id = cd.category_id
LEFT join oc_category c2 on (c.parent_id = c2.category_id)
LEFT join oc_category_description cd2 on c2.category_id = cd2.category_id
LEFT join oc_category c3 on (c2.parent_id = c3.category_id)
LEFT join oc_category_description cd3 on c3.category_id = cd3.category_id
where
p.status = 1
I develop new filter in admin opencart.
But my sql request is don't work
Field "value" is declared in table oc_order_option
Sql request without my filter
SELECT o.order_id, CONCAT(o.lastname, ' ', o.firstname) AS customer, COUNT(po.pass_id) as passengers, m.name as carrier, cd.name as tour, o.shipping_code, o.total, os.name as order_status, o.currency_code, o.currency_value, o.date_added, o.date_modified
FROM oc_order o
LEFT JOIN oc_agent_to_order ato ON ato.order_id = o.order_id
JOIN oc_order_option oo ON oo.order_id = o.order_id
JOIN oc_order_status os ON os.order_status_id = o.order_status_id
JOIN oc_passenger_to_order po ON o.order_id = po.order_id
JOIN oc_passenger pfo ON po.pass_id = pfo.pass_id
JOIN oc_order_product op ON op.order_id = o.order_id
JOIN oc_product p ON p.product_id = op.product_id
JOIN oc_manufacturer m ON m.manufacturer_id = p.manufacturer_id
JOIN oc_product_to_category ptc ON ptc.product_id = p.product_id AND ptc.main_category = 1
JOIN oc_category_description cd ON cd.category_id = ptc.category_id
WHERE o.order_status_id > '0'
I try this sql code for my request
AND value BETWEEN '10.04.2019' AND '10.04.2019'
Full code:
SELECT o.order_id, CONCAT(o.lastname, ' ', o.firstname) AS customer, COUNT(po.pass_id) as passengers, m.name as carrier, cd.name as tour, o.shipping_code, o.total, os.name as order_status, o.currency_code, o.currency_value, o.date_added, o.date_modified
FROM oc_order o
LEFT JOIN oc_agent_to_order ato ON ato.order_id = o.order_id
JOIN oc_order_option oo ON oo.order_id = o.order_id
JOIN oc_order_status os ON os.order_status_id = o.order_status_id
JOIN oc_passenger_to_order po ON o.order_id = po.order_id
JOIN oc_passenger pfo ON po.pass_id = pfo.pass_id
JOIN oc_order_product op ON op.order_id = o.order_id
JOIN oc_product p ON p.product_id = op.product_id
JOIN oc_manufacturer m ON m.manufacturer_id = p.manufacturer_id
JOIN oc_product_to_category ptc ON ptc.product_id = p.product_id AND ptc.main_category = 1
JOIN oc_category_description cd ON cd.category_id = ptc.category_id
WHERE o.order_status_id > '0' AND value BETWEEN '10.04.2019' AND '10.04.2019'
Does it work if you use a proper date format for the constants?
value BETWEEN '2019-04-10' AND '2019-04-10'
This is, of course, equivalent to:
value = '2019-04-10'
If value is a date/time value, then this only matches at midnight on 2019-04-10. I suspect that you might want:
value >= '2019-04-10' AND
value < '2019-04-11'
I have about 140k raws in all these tables:
SELECT COUNT( DISTINCT p.product_id ) AS total
FROM bh_product p
LEFT JOIN bh_product_description pd ON ( p.product_id = pd.product_id )
LEFT JOIN bh_product_to_store p2s ON ( p.product_id = p2s.product_id )
Is it normal that execution of this query takes about 3 seconds?
All tables have indexes on product_id field.
Can it be somehow improved?
UPDATED:
Original query:
SELECT COUNT( DISTINCT p.product_id ) AS total
FROM bh_product p
LEFT JOIN bh_product_description pd ON ( p.product_id = pd.product_id )
LEFT JOIN bh_product_to_store p2s ON ( p.product_id = p2s.product_id )
WHERE pd.language_id = '2'
AND p.status = '1'
AND p.date_available <= NOW( )
AND p2s.store_id = '0'
AND (
pd.name LIKE '%душевые%'
OR pd.tag LIKE '%душевые%'
OR LCASE( p.model ) = 'душевые'
OR LCASE( p.sku ) = 'душевые'
OR LCASE( p.upc ) = 'душевые'
OR LCASE( p.ean ) = 'душевые'
OR LCASE( p.jan ) = 'душевые'
OR LCASE( p.isbn ) = 'душевые'
OR LCASE( p.mpn ) = 'душевые'
)
UPDATED: It figured out that the server were running other intensive process, that was slowing sql processing.
After turning off other process perfomance become acceptable.
If you are using left join your result will be same with
select count(distinct p.product_id) as total
from bh_product p
because left join could filter nothing by your product_id.
You can start from this query:
SELECT COUNT(
DISTINCT p.product_id ) AS total
FROM bh_product p
INNER JOIN bh_product_description pd
ON p.product_id = pd.product_id
AND pd.language_id = 2
INNER JOIN bh_product_to_store p2s
ON p.product_id = p2s.product_id
AND p2s.store_id = 0
WHERE p.status = '1'
AND p.date_available <= NOW( )
AND (
pd.name LIKE '%душевые%'
OR pd.tag LIKE '%душевые%'
OR 'душевые' IN ( p.model , p.sku , p.upc , p.ean , p.jan , p.isbn , p.mpn ))
But your most weak point here is your WHERE clause. you are trying to search everywhere. That is not very smart. I am pretty sure that p.ean is barcode and can't be equal to душевые same for p.isbn. So you should change your query to do only what you really need to do. But not filter everything with hope to "catch the fish".
Update Check this query (should be much faster then your 1st one):
SELECT COUNT(
DISTINCT p.product_id ) AS total
FROM bh_product p
INNER JOIN bh_product_description pd
ON p.product_id = pd.product_id
AND pd.language_id = 2
INNER JOIN bh_product_to_store p2s
ON p.product_id = p2s.product_id
AND p2s.store_id = 0
I think You are trying to execute query like this
SELECT COUNT( DISTINCT p.product_id ) AS total
FROM bh_product p ,bh_product_description pd,bh_product_to_store p2s where
p.product_id = pd.product_id and p.product_id = p2s.product_id ;
I have the following MySQL query. As you can see in the last line, it asks for the filter_id to be either 51 or 8.
How can I modify this query to make sure the products that are returned are only products that have BOTH filter IDs.
What I did: I tried adding HAVING COUNT(DISTINCT pf.filter_id) >=2 based on other answers in this forum but it did not help.
SELECT COUNT(DISTINCT p.product_id) AS total
FROM ocb3l_product_to_category p2c
LEFT JOIN ocb3l_product_filter pf ON (p2c.product_id = pf.product_id)
LEFT JOIN ocb3l_product p ON (pf.product_id = p.product_id)
LEFT JOIN ocb3l_product_description pd ON (p.product_id = pd.product_id)
LEFT JOIN ocb3l_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 p2c.category_id = '146'
AND pf.filter_id IN (51,8)
P.S. This query is used in an OpenCart shop to get the total number of products on the category pages.
The HAVING COUNT(DISTINCT pf.filter_id) >=2 clause will work, if you were to GROUP BY the product_id.
One approach is to use an inline view (derived table) so that this check can be performed for each product_id. The result from that can be joined to the other tables.
For example:
SELECT COUNT(DISTINCT fp.product_id) AS total
FROM (
SELECT p.product_id
FROM ocb3l_product p
JOIN ocb3l_product_filter pf
ON pf.product_id = p.product_id
AND pf.filter_id IN (51,8)
WHERE p.status = '1'
AND p.date_available <= NOW()
GROUP BY p.product_id
HAVING COUNT(DISTINCT pf.filter_id) = 2
) fp
JOIN ocb3l_product_to_category p2c
ON p2c.product_id = fp.product_id
AND p2c.category_id = '146'
JOIN ocb3l_product_to_store p2s
ON p2s.product_id = fp.product_id
AND p2s.store_id = '0'
JOIN ocb3l_product_description pd
ON pd.product_id = fp.product_id
AND pd.language_id = '1'
What you need to do is add another JOINed copy of the product_filter table like this:
SELECT COUNT(DISTINCT p.product_id) AS total
FROM ocb3l_product_to_category p2c
LEFT JOIN ocb3l_product_filter pf ON (p2c.product_id = pf.product_id)
LEFT JOIN ocb3l_product_filter pf2 ON (p2c.product_id = pf2.product_id) /*new*/
LEFT JOIN ocb3l_product p ON (pf.product_id = p.product_id)
LEFT JOIN ocb3l_product_description pd ON (p.product_id = pd.product_id)
LEFT JOIN ocb3l_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 p2c.category_id = '146'
AND pf.filter_id = 51 /*used to be IN (51,8)*/
AND pf2.filter_id = 8 /*new*/
I have to get products in multiples categories (Prestashop database).
This my query :
SELECT COUNT( cp.`id_product` ) AS total
FROM `ps_product` p
INNER JOIN ps_product_shop product_shop ON ( product_shop.id_product = p.id_product
AND product_shop.id_shop =1 )
LEFT JOIN `ps_category_product` cp ON p.`id_product` = cp.`id_product`
WHERE cp.`id_category` =6
AND cp.`id_category` =126
AND product_shop.`visibility`
IN (
"both", "catalog"
)
AND product_shop.`active` =1
I want to select inside category 6 AND inside category 126, but my query return 0.
A product can have multiples categories, so i want to select only if products are inside the two categories.
How can this be fixed, so I am getting the expected result?
SELECT COUNT( cp.id_product ) AS total
FROM ps_product p
Left JOIN ps_product_shop product_shop ON ( product_shop.id_product = p.id_product
AND product_shop.id_shop =1 )
LEFT JOIN ps_category_product cp ON p.id_product = cp.id_product
WHERE cp.id_category in(6,126)
AND product_shop.visibility IN ('both', 'catalog')
AND product_shop.active =1
Friend Try this,
SELECT COUNT( cp.id_product ) AS total
FROM ps_product p
Left JOIN ps_product_shop product_shop ON ( product_shop.id_product = p.id_product
AND product_shop.id_shop =1 )
LEFT JOIN ps_category_product cp ON p.id_product = cp.id_product
and cp.id_category in(6)
LEFT JOIN ps_category_product cp1 ON p.id_product = cp1.id_product
and cp1.id_category in(126)
WHERE cp.id_category is not null
and cp1.id_category is not null
AND product_shop.visibility IN ('both', 'catalog')
AND product_shop.active =1
Use
WHERE cp.`id_category` =6
OR cp.`id_category` =126
Do u mean between 6 and 126? It is not possible to validate against one column for both 6 and 126. If it is between then use,
SELECT COUNT( cp.`id_product` ) AS total
FROM `ps_product` p
INNER JOIN ps_product_shop product_shop ON ( product_shop.id_product = p.id_product
AND product_shop.id_shop =1 )
LEFT JOIN `ps_category_product` cp ON p.`id_product` = cp.`id_product`
WHERE cp.`id_category` between 6 and 126
AND product_shop.`visibility`
IN (
"both", "catalog"
)
AND product_shop.`active` =1
WHERE (cp.`id_category` = 6 OR cp.`id_category` = 126)
AND product_shop.`visibility` IN ("both", "catalog")
AND product_shop.`active` = 1
In both categories:
SELECT COUNT( cp.id_product ) AS total
FROM ps_product p
Left JOIN ps_product_shop product_shop ON (product_shop.id_product = p.id_product
AND product_shop.id_shop = 1)
WHERE product_shop.visibility IN ('both', 'catalog')
AND product_shop.active = 1
AND EXISTS(SELECT * FROM ps_category_product cp
WHERE p.id_product = cp.id_product AND cp.id_category = 6)
AND EXISTS(SELECT * FROM ps_category_product cp
WHERE p.id_product = cp.id_product AND cp.id_category = 12)