mySql Distinct - group by issue - mysql

I'm trying to find out the most purchased products but to only count distinct users ids. Basically my client wants to stop duplicate purchases from the same user, so that they can't affect the chart/best sellers.
I need to count all order_items for that product, using only Distinct users ids. Currently the results are counting all order_items so the Distinct isn't working.
Any help and I would be grateful.
Thanks in advance
SELECT *
FROM
( SELECT DISTINCT
order_item_meta_3.meta_value as distinct_user_order_items_id,
order_item_meta_2.meta_value as product_id,
SUM( order_item_meta.meta_value ) as item_quantity
FROM
wp_woocommerce_order_items as order_items
LEFT JOIN wp_woocommerce_order_itemmeta as order_item_meta
ON order_items.order_item_id = order_item_meta.order_item_id
LEFT JOIN wp_woocommerce_order_itemmeta as order_item_meta_2
ON order_items.order_item_id = order_item_meta_2.order_item_id
LEFT JOIN wp_woocommerce_order_itemmeta as order_item_meta_3
ON order_items.order_item_id = order_item_meta_3.order_item_id
LEFT JOIN wp_posts AS posts
ON order_items.order_id = posts.ID
LEFT JOIN wp_term_relationships AS rel
ON posts.ID = rel.object_ID
LEFT JOIN wp_term_taxonomy AS tax
USING( term_taxonomy_id )
LEFT JOIN wp_terms AS term
USING( term_id )
WHERE
posts.post_type = 'shop_order'
AND posts.post_status = 'publish'
AND tax.taxonomy = 'shop_order_status'
AND term.slug IN ('completed','processing','on-hold')
AND order_items.order_item_type = 'line_item'
AND order_item_meta.meta_key = '_qty'
AND order_item_meta_2.meta_key = '_product_id'
AND order_item_meta_3.meta_key = '_user_id'
GROUP BY
order_item_meta_2.meta_value
ORDER BY
item_quantity DESC ) as order_table,
wp_posts
LEFT JOIN wp_postmeta as mk1
ON wp_posts.ID = mk1.post_id
LEFT JOIN wp_postmeta as mk2
ON wp_posts.ID = mk2.post_id
WHERE
order_table.product_id = wp_posts.ID
AND wp_posts.ID = mk1.post_id
AND mk1.meta_key = 'is_album'
AND mk1.meta_value = 0
AND mk2.meta_key = '_price'
AND mk2.meta_value = 0

Wouldn't you need to do the sum outside the group by. you have to materialize the distinct set first then aggregate it...
so change first few lines to...
SELECT distinct_user_order_items_Id, product_Id, sum(item_Quantity) as item_Quantity
FROM (
SELECT
order_item_meta_3.meta_value as distinct_user_order_items_id,
order_item_meta_2.meta_value as product_id,
order_item_meta.meta_value as item_quantity

Related

Getting number of purchased items using SQL - Woocommerce

I'm stuck in this query for while and any type of help would be appreciated. This is for a wordpress website which uses woocommerce.
Trying to get purchase details of customers and I need to get a result set which should contain following fields.
Email | First Name | Orders | Items Purchased | Order Total
I've written the following SQL for this purpose. achg8 is the table prefix. An order may have one or more items.
SELECT
pm1.meta_value as email ,
pm2.meta_value as first_name,
sum(pm3.meta_value) as total,
count(posts.ID) as orders ,
count(items.order_item_id) as items
from achg8_posts as posts
left join achg8_postmeta as pm1 on posts.ID = pm1.post_id
left join achg8_postmeta as pm2 on posts.ID = pm2.post_id
left join achg8_postmeta as pm3 on posts.ID = pm3.post_id
left join achg8_woocommerce_order_items as items on items.order_id = posts.ID
WHERE
posts.post_type = 'shop_order' and
posts.post_status = 'wc-processing' and
pm1.meta_key='_billing_email' and
pm2.meta_key='_billing_first_name' and
pm3.meta_key='_order_total'
GROUP by email
The problem is order number and item numbers are always equal. but that's not the case actually.
Need and insight on what i'am doing wrong.
UPDATE
edited the sql to the following as per #matigo's comment. The problem now is the order total gets added up multiple times. For an example if an order has two items (i.e two rows in the joined resultset) order-total gets added up twice.
SELECT
pm1.meta_value as email ,
pm2.meta_value as first_name,
sum(pm3.meta_value) as total,
count(DISTINCT posts.ID) as orders ,
count(items.order_item_id) as items
from achg8_posts as posts
left join achg8_postmeta as pm1 on posts.ID = pm1.post_id
left join achg8_postmeta as pm2 on posts.ID = pm2.post_id
left join achg8_postmeta as pm3 on posts.ID = pm3.post_id
left join achg8_woocommerce_order_items as items on items.order_id = posts.ID
WHERE
posts.post_type = 'shop_order' and
posts.post_status = 'wc-processing' and
pm1.meta_key='_billing_email' and
pm2.meta_key='_billing_first_name' and
pm3.meta_key='_order_total'
GROUP by email
Assuming that the same order number can appear in items multiple times, it looks like you need a DISTINCT in your COUNT.
Try this:
SELECT pm1.`meta_value` as `email`,
pm2.`meta_value` as `first_name`,
SUM(pm3.`meta_value`) as `total`,
COUNT(posts.`ID`) as `orders`,
(SELECT COUNT(z.`order_item_id`)
FROM `achg8_woocommerce_order_items` z
WHERE posts.`ID` = z.`order_id`) as `items`
FROM `achg8_posts` posts INNER JOIN `achg8_postmeta` pm1 ON posts.`ID` = pm1.`post_id`
INNER JOIN `achg8_postmeta` pm2 ON posts.`ID` = pm2.`post_id`
INNER JOIN `achg8_postmeta` pm3 ON posts.`ID` = pm3.`post_id`
WHERE posts.`post_type` = 'shop_order'
and posts.`post_status` = 'wc-processing'
and pm1.`meta_key` = '_billing_email'
and pm2.`meta_key` = '_billing_first_name'
and pm3.`meta_key` = '_order_total'
GROUP by `email`, `first_name`
This should give you exactly what you're looking for 👍🏻
Can you try this and see if it works.
Sorry, I removed that joins without considering the relation with meta_key, can you try this.
SELECT
pm1.`meta_value` as `email`,
pm2.`meta_value` as `first_name`,
SUM(pm3.`meta_value`) as `total`,
COUNT(distinct posts.`ID`) as `orders`,
COUNT(distinct items.order_item_id) as `items`
FROM `achg8_posts` posts
INNER JOIN `achg8_postmeta` pm1 ON posts.`ID` = pm1.`post_id`
INNER JOIN `achg8_postmeta` pm2 ON posts.`ID` = pm2.`post_id`
INNER JOIN `achg8_postmeta` pm3 ON posts.`ID` = pm3.`post_id`
INNER JOIN achg8_woocommerce_order_items as items on items.order_id = posts.ID
WHERE
posts.`post_type` = 'shop_order' and
posts.`post_status` = 'wc-processing' and
pm1.`meta_key` = '_billing_email' and
pm2.`meta_key` = '_billing_first_name' and
pm3.`meta_key` = '_order_total'
GROUP by `email`

COUNT() not displaying correct result

I'm having trouble with my code.
SELECT * FROM wp_posts as wposts
LEFT JOIN wp_term_relationships as rs ON (rs.object_id = wposts.ID)
LEFT JOIN wp_postmeta m1 ON (wposts.ID = m1.post_id )
WHERE (wposts.post_type = 'product' AND wposts.post_status = 'publish')
AND ( m1.meta_key = '_stock_status' AND m1.meta_value = 'instock' )
Now the problem is, some of the items are duplicated that's why it displays wrong count.
https://www.screencast.com/t/cmOku8G3nAF
What am I doing wrong?
If you want just a count of posts, remove the group by and select count(distinct wposts.ID).

My SQL query pulls inaccurate information about variable woocommerce products, but works fine for regular products. Why?

I have a rather long and complicated sql query that I use to pull product reports from Woocommerce (because the browser reports do not contain enough information for my superiors' liking) For the most part, it works wonderfully. But it gives me incorrect/unreliable data for variable products, and I am not sure why this is.
Query follows:
SELECT p.ID, b.meta_value, p.post_title, pv.meta_value, SUM( qty.meta_value ), var.meta_value, "CR [4/3]", SUM( tot.meta_value ), "Avg Prc [6/4] 3?", pr.meta_value, AVG(aic.meta_value) , "Grs Prft [(8-9)/8]", "GrAvPrft [(7-9)/7]", "Grs Markup [(8-9)/8]"
FROM wp_posts p INNER JOIN wp_woocommerce_order_itemmeta pid ON p.ID = pid.meta_value AND pid.meta_key = '_product_id'
INNER JOIN wp_woocommerce_order_itemmeta qty ON pid.order_item_id = qty.order_item_id AND qty.meta_key = '_qty'
INNER JOIN wp_woocommerce_order_itemmeta tot ON tot.order_item_id = qty.order_item_id AND tot.meta_key = '_line_total'
LEFT JOIN wp_woocommerce_order_itemmeta var ON var.order_item_id = qty.order_item_id AND var.meta_key = '_variation_id'
LEFT JOIN wp_woocommerce_order_itemmeta shp ON shp.order_item_id = qty.order_item_id AND shp.meta_key = '_per_product_shipping_cost'
LEFT JOIN wp_postmeta pr ON pr.post_id = p.ID AND pr.meta_key = '_price'
LEFT JOIN wp_postmeta b ON b.post_id = p.ID and b.meta_key = '_bucket'
LEFT JOIN wp_postmeta pv ON p.ID = pv.post_id and pv.meta_key = '_page_views'
LEFT JOIN wp_woocommerce_order_itemmeta aic ON aic.order_item_id = pid.order_item_id and aic.meta_key='_actual_item_cost'
INNER JOIN wp_woocommerce_order_items oim ON oim.order_item_id = pid.order_item_id
INNER JOIN wp_posts ord ON oim.order_id = ord.ID
WHERE p.post_type = 'product'
AND oim.order_item_type = 'line_item'
AND tot.meta_value > 0
AND ord.post_status IN ('wc-completed', 'wc-processing')
GROUP BY p.ID;
Some of the stuff in the select statement is just placeholders for post-query calculations, just ignore those. My main issue is that SUM( qty.meta_value ) and SUM( tot.meta_value ) give incorrect data for variable products.

mysql sum returning wrong value

Hi there so i have this problem in the following query, inside wp_wti_like_post i have number of rows with similar post_id and with value column as 1 or -1.
So let's say for post with id 727 i have only one row , so the sum should be 1, but don't know why it does return 4 and when there are two rows with 727 it does return 8 query is below:
SELECT wp_posts. * ,
SUM( wp_wti_like_post.value ) -4 AS total_sum,
wp_wti_like_post.post_id
FROM wp_posts
INNER JOIN wp_term_relationships ON ( wp_posts.ID =
wp_term_relationships.object_id )
INNER JOIN wp_term_taxonomy ON ( wp_term_relationships.term_taxonomy_id =
wp_term_taxonomy.term_taxonomy_id )
JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
LEFT JOIN wp_wti_like_post ON ( wp_posts.ID = wp_wti_like_post.post_id )
WHERE wp_term_taxonomy.taxonomy = 'category'
AND wp_term_taxonomy.term_id IN ('$c_cid')
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish')
GROUP BY wp_posts.ID
HAVING SUM( wp_wti_like_post.value ) > $min_like
ORDER BY wp_posts.post_date DESC
You are using joins among many tables and there may b a chance that any of them has many associations for a post_id therefore your sum is incorrect i suggest you to use a sub select for your like table and calculate sum in sub select and then join with your main query
SELECT
p.*, COALESCE(l.sum_like,0) AS total_sum,
l.post_id
FROM
wp_posts p
INNER JOIN wp_term_relationships ttr
ON (p.ID = ttr.object_id)
INNER JOIN wp_term_taxonomy tt
ON (ttr.term_taxonomy_id = tt.term_taxonomy_id)
LEFT JOIN (
SELECT post_id ,SUM(`value`) sum_like
FROM wp_wti_like_post
GROUP BY post_id
) l ON (p.ID = l.post_id)
WHERE tt.taxonomy = 'category'
AND tt.term_id IN ('21')
AND p.post_type = 'post'
AND (p.post_status = 'publish')
HAVING total_sum > 2
ORDER BY p.post_date DESC
Also note i have removed wp_postmeta join because its not used in your selection criteria and neither in your filter criteria also wp_postmeta stores different attributes for each post so i guess this table is producing more rows thats why wrong sum is calculated.
Removed -4 from query

WooCommerce query order totals grouped by users with specific role

I need to list all users with a specific role (custom role 'forhandler') and for each show their totals (spent) on published orders that have status 'completed', 'processing' and 'on-hold', along with a count of the number of orders per user (also published and status as above). The result must be sorted with the highest totals first.
I managed to write a SQL query that works (and that's the limit of my SQL knowledge), but it takes 20 seconds+ when running on production data (1200 orders and increasing). Can this query be rewritten to something more efficient (or simply better)?
SELECT users.ID, users.display_name,
(SELECT COUNT(posts.ID)
FROM $wpdb->posts AS posts
LEFT JOIN $wpdb->postmeta ON $wpdb->postmeta.post_id = posts.ID
LEFT JOIN $wpdb->term_relationships AS rel ON posts.ID=rel.object_ID
LEFT JOIN $wpdb->term_taxonomy AS tax USING( term_taxonomy_id )
LEFT JOIN $wpdb->terms AS term USING( term_id )
WHERE $wpdb->postmeta.meta_key = '_customer_user'
AND $wpdb->postmeta.meta_value = users.ID
AND posts.post_type = 'shop_order'
AND posts.post_status = 'publish'
AND tax.taxonomy = 'shop_order_status'
AND term.slug IN ('completed', 'processing', 'on-hold')
) AS numOrders,
(
SELECT SUM(postmeta.meta_value)
FROM $wpdb->postmeta AS postmeta
LEFT JOIN $wpdb->posts AS pp ON pp.ID = postmeta.post_id
LEFT JOIN $wpdb->postmeta AS pm2 ON pm2.post_id = postmeta.post_id
LEFT JOIN $wpdb->term_relationships AS rel ON pp.ID=rel.object_ID
LEFT JOIN $wpdb->term_taxonomy AS tax USING( term_taxonomy_id )
LEFT JOIN $wpdb->terms AS term USING( term_id )
WHERE postmeta.meta_key = '_order_total'
AND pm2.meta_key = '_customer_user'
AND pm2.meta_value = users.ID
AND tax.taxonomy = 'shop_order_status'
AND term.slug IN ('completed', 'processing', 'on-hold')
AND pp.post_type = 'shop_order'
AND pp.post_status = 'publish'
) AS totalsOfOrders
FROM wp_users AS users
INNER JOIN wp_usermeta ON users.ID = wp_usermeta.user_id
WHERE wp_usermeta.meta_key = 'wp_capabilities'
AND wp_usermeta.meta_value LIKE '%forhandler%'
ORDER BY totalsOfOrders DESC