简体   繁体   中英

MySQL Select Query - Use Case When or Join?

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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM