what's wrong with my sql query - mysql

Id like it to return records where products_extrafield_id is not 14 , but it still RETURNS it in my results .. I'm using joins
SELECT op. *
FROM
products_to_products_extra_fields AS p
INNER JOIN orders_products AS op ON p.products_id = op.products_id
INNER JOIN orders AS o ON op.orders_id = o.orders_id
WHERE NOT
EXISTS (
SELECT *
FROM products_to_products_extra_fields
WHERE
p.products_id = op.products_id
AND p.products_extra_fields_id = 14
)
AND o.date_purchased BETWEEN '2013-11-29' AND '2013-12-03 23:59:59'
AND o.payment_method = 'Institutional Billing'
AND o.orders_status <100001
GROUP BY o.orders_id
ORDER BY DECODE( o.cc_type, 'oFsAfHr7' ) ASC
LIMIT 0 , 30

If I am reading your SQL correctly, then you don't need a NOT EXISTS clause to do this. Just replace the NOT EXISTS clause with the following statement: p.products_extra_fields_id != 14
SELECT
op. *
FROM
products_to_products_extra_fields AS p
INNER JOIN orders_products AS op
ON p.products_id = op.products_id
INNER JOIN orders AS o
ON op.orders_id = o.orders_id
WHERE
p.products_extra_fields_id != 14
AND o.date_purchased BETWEEN '2013-11-29' AND '2013-12-03 23:59:59'
AND o.payment_method = 'Institutional Billing'
AND o.orders_status <100001
GROUP BY o.orders_id
ORDER BY DECODE( o.cc_type, 'oFsAfHr7' ) ASC
LIMIT 0 , 30

Why are you GROUPing without using aggregate functions? Also, why would try to GROUP BY a field that is not in your SELECT? I added the DISTINCT operator, along with moving your logic around. You subquery was using criteria from the main/ outer query.
SELECT DISTINCT o.cc_type, op.*
FROM orders_products AS op
INNER JOIN orders AS o
ON op.orders_id = o.orders_id
WHERE o.date_purchased BETWEEN '2013-11-29' AND '2013-12-03 23:59:59'
AND o.payment_method = 'Institutional Billing'
AND o.orders_status <100001
AND NOT EXISTS (SELECT *
FROM products_to_products_extra_fields AS p
WHERE p.products_id = op.products_id
AND p.products_extra_fields_id = 14)
ORDER BY DECODE( o.cc_type, 'oFsAfHr7' ) ASC
LIMIT 0 , 30;

Related

MySQL error: Subquery returns more than 1 row when trying to insert values

I have the following MySQL script. What I'm trying to do is:
Get the 100 bestselling products
Get their prices
Calculate 20% off the price
Then insert the new price into the specials table
This works well when I change the limit on my subqueries to 1, but how can I do this for all 100 products in one script?
Here is the error I'm receiving: Subquery returns more than 1 row
INSERT INTO oc_product_special (product_id, customer_group_id, priority, price, date_start, date_end)
VALUES (
(SELECT op.product_id
FROM oc_order_product op
LEFT JOIN oc_order o
ON (op.order_id = o.order_id)
LEFT JOIN oc_product p ON (op.product_id = p.product_id)
LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id)
WHERE o.order_status_id > '0'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = 0
GROUP BY op.product_id
ORDER BY COUNT(*) DESC
LIMIT 100),
"1","20",
(SELECT p.price * 0.8 AS "price"
FROM oc_order_product op
LEFT JOIN oc_order o
ON (op.order_id = o.order_id)
LEFT JOIN oc_product p ON (op.product_id = p.product_id)
LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id)
WHERE o.order_status_id > '0'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = 0
GROUP BY op.product_id
ORDER BY COUNT(*) DESC
LIMIT 100),
"2014-11-11","2030-01-01"
)
Thanks for any help.
Don't use VALUES when you want to insert all the results of a SELECT. Just use the SELECT:
INSERT INTO oc_product_special (product_id, customer_group_id, priority, price, date_start, date_end)
SELECT op.product_id, "1", "20", p.price * 0.8, "2014-11-11", "2030-01-01"
FROM oc_order_product op
LEFT JOIN oc_order o
ON (op.order_id = o.order_id)
LEFT JOIN oc_product p ON (op.product_id = p.product_id)
LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id)
WHERE o.order_status_id > '0'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = 0
GROUP BY op.product_id
ORDER BY COUNT(*) DESC
LIMIT 100
The format is wrong, to insert multiple records you should do something like this:
INSERT INTO SomeTable ( Col1, Col2, Col3 )
SELECT Val1, Val2, Val3 FROM SomeOtherTable

OR clause slowing down SQL query

I need your help about the query below which takes more than 2 min to return a result:
SELECT
p.weight,
o.login,
o.date,
o.s_address,
o.s_city,
o.s_county,
o.s_state,
o.s_country,
o.s_zipcode,
o.phone,
c.categoryid,
c.category,
o.orderid,
p.product product_name,
p.productcode sku,
d.amount,
v.value emplacement,
( SELECT ev.value FROM xcart_extra_field_values ev LEFT JOIN xcart_extra_fields ef ON ef.fieldid=ev.fieldid WHERE ev.productid = d.productid AND ef.field = 'a_type' LIMIT 1 ) type,
o.customer_notes,
o.membership,
o.s_firstname,
o.s_lastname,
o.phone,
d.price,
o.email
FROM `xcart_orders` o
LEFT JOIN `xcart_shipping` s ON s.shippingid=o.shippingid
LEFT JOIN `xcart_order_details` d ON d.orderid=o.orderid
LEFT JOIN `xcart_products` p ON p.productid=d.productid
LEFT JOIN `xcart_products_categories` pc ON pc.productid=p.productid
LEFT JOIN `xcart_categories` c ON c.categoryid=pc.categoryid
LEFT JOIN `xcart_extra_field_values` v ON v.productid=p.productid
LEFT JOIN `xcart_extra_fields` f ON f.fieldid=v.fieldid
WHERE o.shippingid IN ( SELECT DISTINCT shippingid FROM `xcart_rafale_shipping` WHERE rafale='1' )
AND (
SELECT COUNT(*)
FROM `xcart_order_details` d2
LEFT JOIN `xcart_products_categories` pc2 ON pc2.productid=d2.productid
WHERE d2.orderid=o.orderid
AND pc2.categoryid NOT IN ( SELECT DISTINCT ac2.categoryid FROM `xcart_rafale_aggregation_categories` ac2 WHERE ac2.aggregationid='12' )
) = 0
AND (
( o.date BETWEEN '1386802800' AND '1386889199' )
OR (o.orderid IN ('44', '55', '66'))
)
AND o.orderid NOT IN ('11', '22', '33', '123', '458')
AND o.paid = 'Y'
AND o.status <> 'F'
AND o.status <> 'Q'
AND o.status <> 'I'
AND f.field = 'emplacement'
AND pc.main = 'Y'
ORDER BY v.value ASC, p.productcode ASC
LIMIT 100
The problem may come from the following clause
AND (
( o.date BETWEEN '1386802800' AND '1386889199' )
OR (o.orderid IN ('44', '55', '66'))
)
because the query executes faster when I remove the OR (o.orderid IN ('44', '55', '66'))
There are indexes on o.date and o.orderid columns
I used the query below inspired by reply from #Clockwork-Muse:
SELECT
p.weight,
o.login,
o.date,
o.s_address,
o.s_city,
o.s_county,
o.s_state,
o.s_country,
o.s_zipcode,
o.phone,
c.categoryid,
c.category,
o.orderid,
p.product product_name,
p.productcode sku,
d.amount,
v.value emplacement,
( SELECT ev.value FROM xcart_extra_field_values ev LEFT JOIN xcart_extra_fields ef ON ef.fieldid=ev.fieldid WHERE ev.productid = d.productid AND ef.field = 'a_type' LIMIT 1 ) type,
o.customer_notes,
o.membership,
o.s_firstname,
o.s_lastname,
o.phone,
d.price,
o.email
FROM `xcart_order_details` d
INNER JOIN (SELECT *
FROM `xcart_orders`
WHERE (
orderid IN ('44', '55', '66')
OR (`date` >= '1386802800' AND `date` <= '1386889199')
)
) o
ON o.orderid = d.orderid
INNER JOIN (SELECT DISTINCT shippingid
FROM `xcart_rafale_shipping`
WHERE rafale = '1') rf
ON rf.shippingid = o.shippingid
INNER JOIN `xcart_shipping` s ON s.shippingid=o.shippingid
INNER JOIN `xcart_products` p ON p.productid=d.productid
INNER JOIN (SELECT *
FROM `xcart_products_categories`
WHERE main = 'Y') pc
ON pc.productid=p.productid
LEFT JOIN `xcart_categories` c ON c.categoryid=pc.categoryid
LEFT JOIN `xcart_extra_field_values` v ON v.productid=p.productid
LEFT JOIN `xcart_extra_fields` f ON f.fieldid=v.fieldid
WHERE NOT EXISTS (
SELECT d2.orderid
FROM `xcart_order_details` d2
LEFT JOIN `xcart_products_categories` pc2 ON pc2.productid=d2.productid
WHERE d2.orderid=o.orderid
AND pc2.categoryid NOT IN ( SELECT DISTINCT ac2.categoryid FROM `xcart_rafale_aggregation_categories` ac2 WHERE ac2.aggregationid='12' )
)
AND o.orderid NOT IN ('11', '22', '33', '123', '458')
AND o.paid = 'Y'
AND o.status NOT IN ('F', 'Q', 'I')
AND f.field = 'emplacement'
Besides any other problems your query is having, or indices it may need, it's doing more work than it needs to; here's a slightly tweaked version which might run faster:
SELECT
p.weight,
o.login,
o.date,
o.s_address,
o.s_city,
o.s_county,
o.s_state,
o.s_country,
o.s_zipcode,
o.phone,
c.categoryid,
c.category,
o.orderid,
p.product product_name,
p.productcode sku,
d.amount,
v.value emplacement,
(SELECT ev.value
FROM xcart_extra_field_values ev
INNER JOIN xcart_extra_fields ef
ON ef.fieldid = ev.fieldid
AND ef.field = 'a_type'
WHERE ev.productid = d.productid) type,
o.customer_notes,
o.membership,
o.s_firstname,
o.s_lastname,
o.phone,
d.price,
o.email
FROM `xcart_orders` o
INNER JOIN (SELECT DISTINCT shippingid
FROM `xcart_rafale_shipping`
WHERE rafale = '1') rf
ON rf.shippingid = o.shippingid
LEFT JOIN `xcart_shipping` s
ON s.shippingid = o.shippingid
LEFT JOIN `xcart_order_details` d
ON d.orderid = o.orderid
LEFT JOIN `xcart_products` p
ON p.productid = d.productid
LEFT JOIN `xcart_products_categories` pc
ON pc.productid = p.productid
AND pc.main = 'Y'
LEFT JOIN `xcart_categories` c
ON c.categoryid = pc.categoryid
LEFT JOIN `xcart_extra_field_values` v
ON v.productid = p.productid
LEFT JOIN `xcart_extra_fields` f
ON f.fieldid = v.fieldid
AND f.field = 'emplacement'
WHERE NOT EXISTS (SELECT *
FROM `xcart_products_categories` pc2
LEFT JOIN `xcart_rafale_aggregation_categories` ac2
ON ac2.categoryid = pc2.categoryid
AND ac2.aggregationid = '12'
WHERE pc2.productid = d.productid
AND ac2.categoryid IS NULL)
AND ((o.date >= '1386802800' AND o.date <'1386889200')
OR o.orderid IN ('44', '55', '66'))
AND o.orderid NOT IN ('11', '22', '33', '123', '458')
AND o.paid = 'Y'
AND o.status NOT IN ('F', 'Q', 'I')
ORDER BY v.value ASC, p.productcode ASC
LIMIT 100
A couple of other things -
You have LEFT JOINs with a condition in the WHERE clause - this actually turns them into INNER JOINs. I've moved the relevant conditions into the join, which will likely change your results. If you wanted an actual INNER JOIN, just change/remove the word. This is why it's best to put ALL conditions in a join, when possible.
Date/time/timestamps (even if not stored as that type) are a "measurement" - all measurements logically have some imprecision in the recording; to reflect this please use "lower-bound inclusive, upper-bound exclusive" (a >= x < b, needs to be flipped for negative values) for comparisons. I also recommend this for integer counts, for the sake of consistency.
Without an ORDER BY clause, any use of LIMIT (or similar statements) returns essentially uncontrollable results. If you want exactly one value, you must do one of the following - 1) use an aggregate (MAX(), etc), 2) write your query/structure your db such that only one value will meet the criteria, 3) provide a relevant ORDER BY for the use of "select position x" type constructs. Failure to do so will cause your query to return unexpected results when you least expect it (and without throwing a warning, either). In this case I find it extremely unlikely that there is more than one instance of a value in a EAV table (essentially, case #2).
Your original query contains a rather obfuscated double negative (SELECT COUNT(*) ... = 0)). Unfortunately, without knowing more about the nature of your data/table schema, I can't really eliminate the double negative (although I can make it more obvious. For the sake of future maintainers, please avoid double negatives whenever possible. In this case, it's because of your (perhaps overly) liberal use of LEFT-joins - Are you sure that information isn't required?
Most likely thing to help you would be to make sure you have an index on xcart_orders.orderid if you are sure that part of the query is making it slower.
Try this query, I tried all subquerys put in joins:
SELECT
p.weight,
o.login,
o.date,
o.s_address,
o.s_city,
o.s_county,
o.s_state,
o.s_country,
o.s_zipcode,
o.phone,
c.categoryid,
c.category,
o.orderid,
p.product product_name,
p.productcode sku,
d.amount,
v.value emplacement,
evv.Value AS type,
o.customer_notes,
o.membership,
o.s_firstname,
o.s_lastname,
o.phone,
d.price,
o.email
FROM `xcart_orders` o
LEFT JOIN `xcart_shipping` s ON s.shippingid=o.shippingid
LEFT JOIN `xcart_order_details` d ON d.orderid=o.orderid
LEFT JOIN `xcart_products` p ON p.productid=d.productid
LEFT JOIN `xcart_products_categories` pc ON pc.productid=p.productid
LEFT JOIN `xcart_categories` c ON c.categoryid=pc.categoryid
LEFT JOIN `xcart_extra_field_values` v ON v.productid=p.productid
LEFT JOIN `xcart_extra_fields` f ON f.fieldid=v.fieldid
JOIN (SELECT DISTINCT shippingid
FROM `xcart_rafale_shipping`
WHERE rafale='1') rs
ON rs.shippingid = o.shippingid
JOIN (SELECT d2.orderid, COUNT(*) as cnt
FROM `xcart_order_details` d2
LEFT JOIN `xcart_products_categories` pc2 ON pc2.productid=d2.productid
LEFT JOIN `xcart_rafale_aggregation_categories` ac2
ON ac2.aggregationid='12'
AND ac2.categoryid = pc2.categoryid
WHERE ac2.categoryid is null
GROUP BY d2.orderid
) dd2
ON dd2.orderid=o.orderid
AND dd2.cnt = 0
LEFT JOIN (SELECT ev.productid, MAX(ev.value) as 'Value'
FROM xcart_extra_field_values ev
LEFT JOIN xcart_extra_fields ef ON ef.fieldid=ev.fieldid
WHERE ef.field = 'a_type'
GROUP BY ev.productid) evv
ON evv.productid = d.productid
WHERE (( o.date BETWEEN '1386802800' AND '1386889199' )
OR (o.orderid IN ('44', '55', '66'))
)
AND o.orderid NOT IN ('11', '22', '33', '123', '458')
AND o.paid = 'Y'
AND o.status NOT IN ('F', 'Q', 'I')
AND f.field = 'emplacement'
AND pc.main = 'Y'
ORDER BY v.value ASC, p.productcode ASC
LIMIT 100

This query only returns one results , supposed to return two

This query is supposed to return two order_ids .. but only returning one , and the order_ids meet the conditions of the query ... what could be wrong ?
SELECT r.*
FROM products_to_products_extra_fields AS p
INNER JOIN orders_roster AS r ON p.products_id = r.products_id
INNER JOIN orders AS o on r.orders_id = o.orders_id
WHERE p.products_extra_fields_id = 14 AND
p.products_extra_fields_value between '2013-11-01' and '2013-11-30 23:59:59' AND
r.roster_status != 'Removed' AND
o.payment_method = 'Institutional Billing' AND
o.orders_status < 100001
GROUP BY o.orders_id
ORDER BY DECODE(o.cc_type, 'oFsAfHr7') ASC
Try:
SELECT DISTINCTROW r.* ...
Also, experiment with the GROUP BY clause, which may be causing the rows to collapse on orders_id.

How write mysql query corresponding this tables

Hi database professionals. I need your help
This is my database tables
I want to get this result
How can I write select query to get that result ?
I write this query , but it works very slow (20 minute)
SELECT c.name, p.title, tbl1.count, tbl1.sum,tbl2.count_1, tbl2.sum_1, tbl3.count_2, tbl3.sum_2
FROM `client` c LEFT JOIN
(SELECT c.name, p.id, p.title,p.unit, o.client_id, COUNT(*) AS `count`, SUM(op.price) AS `sum`
FROM `order` o INNER JOIN order_product op ON o.id = op.order_id
INNER JOIN product p ON op.product_id = p.id
INNER JOIN `client` c ON c.id = o.client_id
WHERE MONTH(o.date) = MONTH('2013-07-01') AND YEAR(o.date) = YEAR('2013-07-01') AND p.category_id = 1
GROUP BY c.id, p.id, YEAR(o.date), MONTH(o.date)) AS tbl1 ON c.id = tbl1.client_id
LEFT JOIN
(SELECT p.id, p.title,p.unit, c.name, o.client_id, COUNT(*) AS `count_1`, SUM(op.price) AS `sum_1`
FROM `order` o INNER JOIN order_product op ON o.id = op.order_id
INNER JOIN product p ON op.product_id = p.id
INNER JOIN `client` c ON c.id = o.client_id
WHERE MONTH(o.date) = MONTH(DATE_ADD('2013-07-01', INTERVAL 1 MONTH)) AND
YEAR(o.date) = YEAR(DATE_ADD('2013-07-01', INTERVAL 1 MONTH)) AND p.category_id = 1
GROUP BY c.id, p.id, YEAR(o.date), MONTH(o.date)) AS tbl2 ON c.id = tbl2.client_id
LEFT JOIN
(SELECT p.id, p.title,p.unit, c.name, o.client_id, COUNT(*) AS `count_2`, SUM(op.price) AS `sum_2`
FROM `order` o INNER JOIN order_product op ON o.id = op.order_id
INNER JOIN product p ON op.product_id = p.id
INNER JOIN `client` c ON c.id = o.client_id
WHERE MONTH(o.date) = MONTH(DATE_ADD('2013-07-01', INTERVAL 2 MONTH)) AND
YEAR(o.date) = YEAR(DATE_ADD('2013-07-01', INTERVAL 2 MONTH)) AND p.category_id = 1
GROUP BY c.id, p.id, YEAR(o.date), MONTH(o.date)) AS tbl3 ON c.id = tbl3.client_id
, product p
WHERE (tbl1.id = p.id OR tbl2.id = p.id OR tbl3.id = p.id)
ORDER BY c.name

Need help with a mysql query

I've developed a mysql query that tells me how many times each product was purchased over a specified timeframe. I'm trying to figure out how to join this with my pageview tracking table so I can calculate the conversion rate for each product. Here is the original query:
SELECT SUM( op.products_quantity ) AS num_sold, SUM( op.final_price * op.products_quantity ) AS total_sales, p.products_model, pd.products_name, p.products_id
FROM orders_products AS op
JOIN products AS p
JOIN products_description AS pd
JOIN orders as o
WHERE p.products_id = op.products_id
AND p.products_id = pd.products_id
AND op.orders_id = o.orders_id
AND o.date_purchased BETWEEN '2011-01-15' AND '2011-04-15"'
GROUP BY p.products_id
ORDER BY total_sales DESC
I have another query that gives me the page views per product:
SELECT pv.products_id, count( pv.timestamp )
FROM products_visits AS pv
WHERE pv.timestamp
BETWEEN '2011-01-15'
AND '2011-04-17'
GROUP BY products_id
The caveat is that the views data has just started being collected, so we want return results even if a given product_id is not in the views table, but is in the purchases table.
How do I combine those queries into a single query?
You need a LEFT OUTER JOIN against a subquery. I think this will do the job:
SELECT
SUM( op.products_quantity ) AS num_sold,
SUM( op.final_price * op.products_quantity ) AS total_sales,
p.products_model, pd.products_name,
p.products_id,
visits.visits
FROM orders_products AS op
JOIN products AS p
JOIN products_description AS pd
JOIN orders as o
LEFT OUTER JOIN (
SELECT pv.products_id, count( pv.timestamp ) AS visits
FROM products_visits AS pv
WHERE pv.timestamp BETWEEN '2011-01-15' AND '2011-04-17'
GROUP BY products_id
) visits ON p.products_id = visits.products_id
WHERE p.products_id = op.products_id
AND p.products_id = pd.products_id
AND op.orders_id = o.orders_id
AND o.date_purchased BETWEEN '2011-01-15' AND '2011-04-15"'
GROUP BY p.products_id
ORDER BY total_sales DESC
You will need to use a LEFT JOIN: "first" you get all products and their sales data, and then you join the views data, if it exists.
try this:
SELECT p.products_id,
count( pv.timestamp ) AS views,
p.products_model AS model,
SUM( op.products_quantity ) AS num_sold,
SUM( op.final_price * op.products_quantity ) AS total_sales,
pd.products_name
FROM products AS p
LEFT JOIN products_visits AS pv
ON pv.products_id = p.products_id
AND pv.timestamp BETWEEN '2011-01-15' AND '2011-04-17'
JOIN orders_products AS op
ON p.products_id = op.products_id
JOIN products_description AS pd
ON p.products_id = pd.products_id
JOIN orders as o
ON op.orders_id = o.orders_id
AND o.date_purchased BETWEEN '2011-01-15' AND '2011-04-17'
GROUP BY p.products_id
ORDER BY total_sales DESC