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'
Related
This is my query and it's to slow... I'm looking for the way to optimize it.
SELECT p.id,
Group_concat(pc.cat_id) AS groups,
p.code,
p.NAME,
p.price,
p.thumbnail,
p.image,
mc.queries AS merch_queries,
mc.position AS merch_position,
Group_concat(op.image) AS option_images,
cf_RETAIL.value AS custom_RETAIL,
cf_rating.value AS custom_rating,
cf_reviews.value AS custom_reviews,
cf_sku.value AS custom_sku,
cf_brand.value AS custom_brand,
cf_custom_thumbnail.value AS custom_custom_thumbnail
FROM s01_products AS p
LEFT JOIN s01_categoryxproduct AS pc
ON p.id = pc.product_id
LEFT JOIN (SELECT pv.product_id,
pv.value
FROM s01_cfm_prodfields AS pf
INNER JOIN s01_cfm_prodvalues AS pv
ON pf.id = pv.field_id
WHERE pf.code = 'RETAIL') AS cf_RETAIL
ON p.id = cf_RETAIL.product_id
LEFT JOIN (SELECT pv.product_id,
pv.value
FROM s01_cfm_prodfields AS pf
INNER JOIN s01_cfm_prodvalues AS pv
ON pf.id = pv.field_id
WHERE pf.code = 'rating') AS cf_rating
ON p.id = cf_rating.product_id
LEFT JOIN (SELECT pv.product_id,
pv.value
FROM s01_cfm_prodfields AS pf
INNER JOIN s01_cfm_prodvalues AS pv
ON pf.id = pv.field_id
WHERE pf.code = 'reviews') AS cf_reviews
ON p.id = cf_reviews.product_id
LEFT JOIN (SELECT pv.product_id,
pv.value
FROM s01_cfm_prodfields AS pf
INNER JOIN s01_cfm_prodvalues AS pv
ON pf.id = pv.field_id
WHERE pf.code = 'sku') AS cf_sku
ON p.id = cf_sku.product_id
LEFT JOIN (SELECT pv.product_id,
pv.value
FROM s01_cfm_prodfields AS pf
INNER JOIN s01_cfm_prodvalues AS pv
ON pf.id = pv.field_id
WHERE pf.code = 'brand') AS cf_brand
ON p.id = cf_brand.product_id
LEFT JOIN (SELECT pv.product_id,
pv.value
FROM s01_cfm_prodfields AS pf
INNER JOIN s01_cfm_prodvalues AS pv
ON pf.id = pv.field_id
WHERE pf.code = 'custom_thumbnail') AS cf_custom_thumbnail
ON p.id = cf_custom_thumbnail.product_id
LEFT JOIN (SELECT p.product_id AS product_id,
Group_concat(q.query) AS queries,
Min(p.position) AS position
FROM s01_srch_merchandisingproduct AS p
LEFT JOIN s01_srch_merchandisingquery AS q
ON q.id = p.query_id
GROUP BY p.product_id) AS mc
ON p.id = mc.product_id
LEFT JOIN s01_options AS op
ON p.id = op.product_id
AND op.image <> ''
WHERE p.active = 1
GROUP BY p.id
Thanks for any help!
Updated Tables Schema:
**s01_categoryxproduct**
cat_id,
product_id,
disp_order
**s01_products**
id
catcount
agrpcount
pgrpcount
disp_order
code
name
thumbnail
image
price
cost
descrip
weight
taxable
active
sku
cancat_id
page_id
page_title
dt_created
dt_updated
**s01_CFM_ProdValues**
field_id,
product_id,
value,
value_long
**s01_CFM_ProdFields**
id,
code,
name,
group_id,
fieldtype,
info,
facet
**s01_Options**
id,
product_id,
attr_id,
disp_order,
code,
prompt,
price,
cost,
weight,
image
**s01_SRCH_MerchandisingProduct**
id,
product_id,
query_id,
position
**s01_SRCH_MerchandisingQuery**
id,
query
"Over-normalization" and EAV are the problems.
Put prodfields and prodvalues in the same table. Splitting them into two tables leads to performance-eating overhead.
More on optimizing an EAV table: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
More discussion of why EAV is bad: http://mysql.rjweb.org/doc.php/eav
SELECT p.id,
Group_concat(pc.cat_id) AS groups,
p.code,
p.NAME,
p.price,
p.thumbnail,
p.image,
mc.queries AS merch_queries,
mc.position AS merch_position,
Group_concat(op.image) AS option_images,
IF(pf.code = 'RETAIL',pv.value , NULL) AS custom_RETAIL,
IF(pf.code = 'rating',pv.value , NULL) AS custom_rating,
IF(pf.code = 'reviews',pv.value , NULL) AS custom_reviews,
IF(pf.code = 'brand',pv.value , NULL) AS custom_brand,
IF(pf.code = 'custom_thumbnail',pv.value , NULL) AS custom_custom_thumbnail,
pvr.value AS custom_rating,
FROM s01_products AS p
LEFT JOIN s01_categoryxproduct AS pc ON p.id = pc.product_id
LEFT JOIN s01_cfm_prodfields AS cf_RETAIL ON p.id = cf_RETAIL.product_id
LEFT JOIN s01_cfm_prodvalues AS pv ON cf_RETAIL.id = pv.field_id
LEFT JOIN (SELECT p.product_id AS product_id,
Group_concat(q.query) AS queries,
Min(p.position) AS position
FROM s01_srch_merchandisingproduct AS p
LEFT JOIN s01_srch_merchandisingquery AS q
ON q.id = p.query_id
GROUP BY p.product_id) AS mc
ON p.id = mc.product_id
LEFT JOIN s01_options AS op
ON p.id = op.product_id
AND op.image <> ''
WHERE p.active = 1
GROUP BY p.id`;
I have been having issues with missing data when I run the following query.
There are some products which has special price, stored in table oc_product_special and some products has regular price stored in table oc_product.
I figured out that it is only showing data if there is a special price in table oc_product_special. it is omitting any data where there is no special price and only regular price. I am not sure how to fix this problem. How and where i can add conditional statement or something like
if there is a regular price present and no special price then show regular price and 0 for special price.
SELECT
pd.name AS 'Product Name',
p.model AS UPC,
p.quantity AS 'Quantity',
p.price AS 'Regular Price',
ps.price AS 'Special Price',
p.cost AS 'COST',
p.status AS 'Status'
FROM oc_product p
INNER JOIN oc_product_description pd
ON pd.product_id = p.product_id
INNER JOIN oc_product_special ps
ON ps.product_id = p.product_id
INNER JOIN oc_manufacturer m
ON p.manufacturer_id = m.manufacturer_id
INNER JOIN oc_product_to_category p2c
ON p2c.product_id = p.product_id
INNER JOIN oc_category c
ON c.category_id = p2c.category_id
INNER JOIN oc_category_description cd
ON c.category_id = cd.category_id
WHERE
c.category_id = 37 OR c.parent_id = 37
GROUP BY pd.name ORDER BY m.name ASC
Use LEFT JOIN, which will retain records on the left side of the join even if they do not match to anything on the right side:
SELECT COALESCE(pd.name, 'NA') AS 'Product Name',
p.model AS UPC,
p.quantity AS 'Quantity',
p.price AS 'Regular Price',
COALESCE(ps.price, 0.0) AS 'Special Price',
p.cost AS 'COST',
p.status AS 'Status'
FROM oc_product p
LEFT JOIN oc_product_description pd
ON pd.product_id = p.product_id
LEFT JOIN oc_product_special ps
ON ps.product_id = p.product_id
INNER JOIN oc_manufacturer m
ON p.manufacturer_id = m.manufacturer_id
INNER JOIN oc_product_to_category p2c
ON p2c.product_id = p.product_id
INNER JOIN oc_category c
ON c.category_id = p2c.category_id
INNER JOIN oc_category_description cd
ON c.category_id = cd.category_id
WHERE c.category_id = 37 OR
c.parent_id = 37
GROUP BY pd.name
ORDER BY m.name
Explanation:
In a LEFT JOIN, when a record on the left side of the join does not match to anything on the right side, the columns from the right side will all appear as NULL in the result set. I used the COALESCE function in my query, which will conditionally replace the first argument with the second if the former be NULL. In this case, the special price will be replaced with zero if NULL. I also used it with the product name in case names be missing in some cases.
use left join on oc_product_special
SELECT
pd.name AS 'Product Name',
p.model AS UPC,
p.quantity AS 'Quantity',
p.price AS 'Regular Price',
ps.price AS 'Special Price',
p.cost AS 'COST',
p.status AS 'Status'
FROM oc_product p
INNER JOIN oc_product_description pd
ON pd.product_id = p.product_id
LEFT JOIN oc_product_special ps
ON ps.product_id = p.product_id
INNER JOIN oc_manufacturer m
ON p.manufacturer_id = m.manufacturer_id
INNER JOIN oc_product_to_category p2c
ON p2c.product_id = p.product_id
INNER JOIN oc_category c
ON c.category_id = p2c.category_id
INNER JOIN oc_category_description cd
ON c.category_id = cd.category_id
WHERE
c.category_id = 37 OR c.parent_id = 37
GROUP BY pd.name ORDER BY m.name ASC
Inner join si for matching value in you case somethings there aren't match so ..use left join
I have this query
MYSQL:
SELECT COUNT(op.quantity) AS quantity_sold, op.model AS model_number,
op.name AS product_name, ptc.category_id, cd.name
FROM ((`order_product` op INNER JOIN `product` p ON op.product_id = p.product_id)
INNER JOIN (`product_to_category` ptc
INNER JOIN `category_description` cd ON ptc.category_id = cd.category_id) ON op.product_id = ptc.product_id)
INNER JOIN `order` o on o.order_id = op.order_id GROUP BY op.model ORDER BY quantity_sold DESC;
I tried this code to count the no. of rows for the above result.
SELECT COUNT(*) AS total FROM ((`order_product` op INNER JOIN `product` p ON op.product_id = p.product_id)
INNER JOIN (`product_to_category` ptc
INNER JOIN `category_description` cd ON ptc.category_id = cd.category_id) ON op.product_id = ptc.product_id)
INNER JOIN `order` o on o.order_id = op.order_id GROUP BY op.model;
But I am unable to get the count single value.
I need the count of rows returned from the first query as a single value for the purpose of pagination.
If you want the row count that your query returns, wrapping it in an outer query should give you what you want:
SELECT COUNT(*) AS row_count FROM (
SELECT
COUNT(op.quantity) AS quantity_sold,
op.model AS model_number,
op.name AS product_name,
ptc.category_id,
cd.name
FROM order_product op
INNER JOIN product p ON op.product_id = p.product_id
INNER JOIN product_to_category ptc ON op.product_id = ptc.product_id
INNER JOIN category_description cd ON ptc.category_id = cd.category_id
INNER JOIN `order` o on o.order_id = op.order_id
GROUP BY op.model
ORDER BY quantity_sold DESC
) A;
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*/
To build a report, I must select some information on the last transaction status of all my customers. Until now, this is what I got:
SELECT c.firstname, c.lastname, d.product_name, o.payment, s.name, h.date_add
FROM ps_orders o
INNER JOIN ps_order_detail d ON d.id_order = o.id_order
INNER JOIN ps_customer c ON c.id_customer = o.id_customer
INNER JOIN ps_order_history h ON o.id_order = h.id_order
INNER JOIN ps_order_state_lang s ON s.id_order_state = h.id_order_state
WHERE s.id_lang =6
GROUP BY c.id_customer
HAVING MAX(h.date_add)
For each customer, this query is selecting the first date (the field h.date_add) when I need of the last one. It seems the MySQL is ignoring the HAVING.
I tried to make a sub-select, but it doesn't work too.
Thanks any answer.
Here, you need to have a subquery which gets the latest date_add for every id_order on table ps_order_history. The result of the subquery is then joined back on the original table ps_order_history provided that it macth on two columns: date_add and id_order.
SELECT c.firstname,
c.lastname,
d.product_name,
o.payment,
s.name,
h.date_add
FROM ps_orders o
INNER JOIN ps_order_detail d ON d.id_order = o.id_order
INNER JOIN ps_customer c ON c.id_customer = o.id_customer
INNER JOIN ps_order_history h ON o.id_order = h.id_order
INNER JOIN
(
SELECT id_order, MAX(date_add) max_date
FROM ps_order_history
GROUP BY id_order
) x ON h.id_order = x.id_order AND
h.date_add = x.max_date
INNER JOIN ps_order_state_lang s ON s.id_order_state = h.id_order_state
WHERE s.id_lang =6
GROUP BY c.id_customer
To get the last date, you need to join it in:
SELECT c.firstname, c.lastname, d.product_name, o.payment, s.name, h.date_add
FROM ps_orders o
INNER JOIN ps_order_detail d ON d.id_order = o.id_order
INNER JOIN ps_customer c ON c.id_customer = o.id_customer
INNER JOIN ps_order_history h ON o.id_order = h.id_order
INNER JOIN ps_order_state_lang s ON s.id_order_state = h.id_order_state
inner join (select o.id_customer, max(oh.date_add) as maxdate from ps_order_history h join ps_order o on h.id_order = o.id_order group by o.id_customer) omax on omax.id_customer = o.id_customer and o.date_add = omax.maxdate
WHERE s.id_lang =6
GROUP BY c.id_customer
Your having clause calculates the maximum date and then succeeds when it is not equal to 0 (which would be most of the time).