Reputation: 4622
I have a simple Select statement as follows:
select p.ID as order_id,
p.post_date,
max(CASE WHEN pm.meta_key = '_billing_email' and p.ID = pm.post_id
THEN pm.meta_value END) as billing_email,
max(CASE WHEN pm.meta_key = '_billing_first_name' and p.ID = pm.post_id
THEN pm.meta_value END) as _billing_first_name,
max(CASE WHEN pm.meta_key = '_billing_last_name' and p.ID = pm.post_id
THEN pm.meta_value END) as _billing_last_name,
max(CASE WHEN pm.meta_key = '_order_total' and p.ID = pm.post_id
THEN pm.meta_value END) as order_total,
max(CASE WHEN pm.meta_key = '_order_tax' and p.ID = pm.post_id
THEN pm.meta_value END) as order_tax,
max(CASE WHEN pm.meta_key = '_paid_date' and p.ID = pm.post_id
THEN pm.meta_value END) as paid_date
from wp_posts as p,
wp_postmeta as pm
where post_type = 'shop_order'
and p.ID = pm.post_id
and
and post_status = 'wc-completed'
group by p.ID
It's been suggested that I should use the JOIN syntax - I assume instead of CASE WHEN. I've started working on a JOIN version but it doesn't appear to be less verbose so far - just wondering if this is indeed best practise and more efficient to process etc?
I'm new to SQL and learning as I go so would love to see examples of how this could be rewritten using JOIN as I might be going about this the wrong way.
Upvotes: 0
Views: 217
Reputation: 1270763
There are basically two methods for pivoting data in MySQL. You should fix your from
clause to have an explicit join
:
from wp_posts p join
wp_postmeta pm
on p.ID = pm.post_id
where p.post_type = 'shop_order' and p.post_status = 'wc-completed'
Your method for combining the data about a post uses aggregation. The join
method looks like:
select p.*,
pm_be.meta_value as billing_email,
pm_fn.meta_value as billing_first_name,
from wp_posts p left join
wp_postmeta pm_be
on p.ID = pm_be.post_id and pm_be.meta_key = '_billing_email' left join
wp_postmeta pm_fn
on p.ID = pm_fn.post_id and pm_fn.meta_key = '_billing_first_name' left join
. . .
where p.post_type = 'shop_order' and p.post_status = 'wc-completed'
If performance is an issue, then it is worth trying both methods. They are not exactly the same.
First, the aggregation method (your method) produces exactly one row per post, regardless of the number of values that might have the same key value. You can get all the values using group_concat()
rather than max()
.
This is an advantage, because the join
method would return multiple rows for a given key, and that is generally not what you want. You can get around it using a group by
, but that incurs overhead.
The join
method is typically going to be faster for getting a handful of columns from the table -- assuming indexes are set up correctly. One advantage of the aggregation method is that adding new keys is basically adds no overhead -- essentially the aggregation is already so expensive that an additional max()
or listagg()
doesn't add very much.
Regardless of the method, there is one simple rule you should follow: Never use commas in the FROM
clause. Always use explicit JOIN
syntax with an ON
clause.
Upvotes: 1
Reputation: 827
Try to use this (using join)
select p.ID as order_id,
p.post_date,
max(CASE WHEN pm.meta_key = '_billing_email' THEN pm.meta_value END) as billing_email,
max(CASE WHEN pm.meta_key = '_billing_first_name' THEN pm.meta_value END) as _billing_first_name,
max(CASE WHEN pm.meta_key = '_billing_last_name' THEN pm.meta_value END) as _billing_last_name,
max(CASE WHEN pm.meta_key = '_order_total' THEN pm.meta_value END) as order_total,
max(CASE WHEN pm.meta_key = '_order_tax' THEN pm.meta_value END) as order_tax,
max(CASE WHEN pm.meta_key = '_paid_date' THEN pm.meta_value END) as paid_date
from wp_posts as p join
wp_postmeta as pm on (p.ID = pm.post_id)
where post_type = 'shop_order'and
and post_status = 'wc-completed'
group by p.ID
you might need to replace p.post_date by max(p.post_date)
select p.ID as order_id,
max(p.post_date),
max(CASE WHEN pm.meta_key = '_billing_email' THEN pm.meta_value END) as billing_email,
max(CASE WHEN pm.meta_key = '_billing_first_name' THEN pm.meta_value END) as _billing_first_name,
max(CASE WHEN pm.meta_key = '_billing_last_name' THEN pm.meta_value END) as _billing_last_name,
max(CASE WHEN pm.meta_key = '_order_total' THEN pm.meta_value END) as order_total,
max(CASE WHEN pm.meta_key = '_order_tax' THEN pm.meta_value END) as order_tax,
max(CASE WHEN pm.meta_key = '_paid_date' THEN pm.meta_value END) as paid_date
from wp_posts as p join
wp_postmeta as pm on (p.ID = pm.post_id)
where post_type = 'shop_order'and
and post_status = 'wc-completed'
group by p.ID
Upvotes: 0