Mysql query, WP custom fields - mysql

I need to select some things from few WP tables, one of which is custom field value with a certain key. Problem is, some of posts don't have custom field with this key but aside of that they match query. So question is, how do I select even posts that doesn't have custom field with this key, but other than that match query? Value of field for the posts that do not have custom field should be set 0. I figured it's something like COALESCE, but I'm either using it wrong or it can't be used in this case. My query so far is:
select lists.id,lists.`type`,lists.`status`,lists.watched_eps, lists.score,wp_posts.post_title,wp_posts.post_name,wp_terms.slug,wp_postmeta.meta_value from anime_lists
INNER JOIN wp_posts ON (wp_posts.ID = lists.post_id )
INNER JOIN wp_postmeta ON (wp_postmeta.post_id= lists.post_id )
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)
INNER JOIN wp_terms ON(wp_terms.term_id = wp_term_taxonomy.term_id)
where lists.id=1
and wp_term_taxonomy.taxonomy = 'category'
and wp_postmeta.meta_key='eps'
group by lists.`post_id`
order by lists.`status`, wp_posts.post_title
As it is, query outputs everything that I need but without these posts that do not have custom field 'eps'. If I remove and wp_postmeta.meta_key='eps' it outputs these posts, but that way I get wrong value in wp_postmeta.meta_value field.

As far as I understand what you want, you can just change your wp_postmeta join to a LEFT JOIN and move the WHERE condition on that table to the join, leaving;
SELECT lists.id, lists.`type`, lists.`status`, lists.watched_eps,
lists.score,wp_posts.post_title,wp_posts.post_name,wp_terms.slug,
wp_postmeta.meta_value
FROM anime_lists
INNER JOIN wp_posts
ON wp_posts.ID = anime_lists.post_id
LEFT JOIN wp_postmeta
ON wp_postmeta.post_id = anime_lists.post_id
AND wp_postmeta.meta_key='eps'
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)
INNER JOIN wp_terms
ON(wp_terms.term_id = wp_term_taxonomy.term_id)
WHERE lists.id=1
AND wp_term_taxonomy.taxonomy = 'category'
GROUP BY lists.`post_id`
ORDER BY lists.`status`, wp_posts.post_title

Related

MySQL Query Multiple LEFT JOIN with WHERE column NOT LIKE

Having trouble finding workable syntax to perform this query
SELECT *
FROM wp_posts
LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
WHERE wp_term_taxonomy.term_id IN (307)
GROUP BY wp_posts.ID
Works fine.
What I'm trying to do is add this
WHERE wp_posts.title NOT LIKE '%lug'
I've tried many variations.. but they all result in error.
Tried
AND WHERE wp_posts.title NOT LIKE '%lug'
after the second WHERE
I've also tried adding it before the LEFT JOIN
Just getting a generic syntax error wherever I try to place it in the query.
the condition of left joined table should be added to on clause and not in where otherwise works as inner join
SELECT *
FROM wp_posts
LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_taxonomy
ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
and wp_term_taxonomy.term_id IN (307)
WHERE wp_posts.title NOT LIKE '%lug'
GROUP BY wp_posts.ID
you should not use group by if you don'have aggregation function (use disticnt if yoy neeed) this behavior is deprecated in sql and in some version is not more allowed

Filter rows without a specific value

I'm querying a wordpress mysql db outside the php language and I don't know how to solve the following problem: each post has taxonomies with some value. There's a value called 'calificaciones' which I'd like to filter on. This is my current query:
SELECT wp_posts.post_title, IF (wp_term_taxonomy.taxonomy = 'calificaciones', wp_terms.slug, 'no') as calificacion
FROM wp_posts
JOIN wp_term_relationships ON (wp_term_relationships.object_id = wp_posts.ID)
JOIN wp_term_taxonomy ON (wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id)
JOIN wp_terms ON (wp_terms.term_id = wp_term_taxonomy.term_id)
AND wp_posts.post_type = 'ultimas-noticias'
#AND wp_term_taxonomy.taxonomy = 'calificaciones'
The problem with this query is that I'll get the post_title multiple times(because there are others taxonomies for each post). I'd like to get the post title and a flag yes-no, if the post has that taxonomy value or not.
Instead of joining the taxonomies on the same query you could use a sub query for the calificacion column.
SELECT wp_posts.post_title, CASE WHEN EXISTS((SELECT *
FROM wp_term_relationships
JOIN wp_term_taxonomy ON (wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id)
JOIN wp_terms ON (wp_terms.term_id = wp_term_taxonomy.term_id)
WHERE (wp_term_relationships.object_id = wp_posts.ID)
AND wp_term_taxonomy.taxonomy = 'calificaciones'
)) THEN 'YES' ELSE 'NO' END as calificacion
FROM wp_posts
WHERE wp_posts.post_type = 'ultimas-noticias'
You can use select distinct
SELECT distinct wp_posts.post_title, IF (wp_term_taxonomy.taxonomy = 'calificaciones', wp_terms.slug, 'no') as calificacion
FROM wp_posts
JOIN wp_term_relationships ON (wp_term_relationships.object_id = wp_posts.ID)
JOIN wp_term_taxonomy ON (wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id)
JOIN wp_terms ON (wp_terms.term_id = wp_term_taxonomy.term_id)
AND wp_posts.post_type = 'ultimas-noticias'
#AND wp_term_taxonomy.taxonomy = 'calificaciones'

How to filter the GROUP_CONCAT in my SELECT

I am trying to SELECT (all of the multiple) comments from Wordpress which relate to a post (wp_comments.comment_content) with GROUP_CONCAT but I only want to select those comments which DON'T contain the text string "status". If there are no comments at all, or only comments which contain "status" I still want to see those records in the result, just without getting anything back for comments.
When I tried putting a condition similar to [WHERE wp_comments.comment_content NOT LIKE "%status%"] at the end of the complete query, records which only have a comment containing "status" don't display AT ALL, I still need to get those records, just without the comments.
I want to try something like the below version but this throws up an error and doesn't spit out any data at all. (The overall query works as expected btw apart from the comment selection section..).
Maybe I am joining the wp_comments table in the wrong place, using the wrong join, not using a properly formatted nested SELECT or similar, maybe it needs a separate SELECT at the end so I can get the comments back I want in a way which doesn't effect which records are selected overall.. not sure..
Any idea what I am doing wrong or how to approach this?
Here is my query, thanks in advance for any kind pointers!
select wp_woocommerce_order_itemmeta.meta_value as firstwoometavalue,
wp_postmeta.meta_value as firstwpmetavalue, Y.meta_value as ymetavalue,
Z.meta_value as zmetavalue, X.meta_value as xmetavalue,
(GROUP_CONCAT(wp_comments.comment_content) as commentcontent
WHERE wp_comments.comment_type = "order_note" AND
wp_comments.comment_content NOT LIKE "%status%")
FROM wp_postmeta
left JOIN wp_postmeta as Y
ON wp_postmeta.post_id = Y.post_id
left JOIN wp_posts
ON wp_postmeta.post_id = wp_posts.ID
left JOIN wp_woocommerce_order_items
ON wp_woocommerce_order_items.order_id = wp_posts.ID
left JOIN wp_woocommerce_order_itemmeta
ON wp_woocommerce_order_itemmeta.order_item_id = wp_woocommerce_order_items.order_item_id
left JOIN wp_woocommerce_order_itemmeta as Z
ON wp_woocommerce_order_itemmeta.order_item_id = Z.order_item_id
left JOIN wp_woocommerce_order_itemmeta as X
ON wp_woocommerce_order_itemmeta.order_item_id = X.order_item_id
left JOIN wp_comments
ON wp_comments.comment_post_ID = wp_posts.ID
where 1=1
AND wp_woocommerce_order_itemmeta.meta_key ="Adults"
AND wp_postmeta.meta_key ="_billing_first_name"
AND Y.meta_key ="_billing_last_name"
AND Z.meta_key ="Booking Type"
AND Z.meta_value LIKE "%'.$showlocation.'%"
AND X.meta_key ="Booking Date"
AND X.meta_value = "'.$showdate.'"
AND wp_posts.post_status ="wc-completed"
GROUP BY wp_posts.ID
This works
SELECT
wp_woocommerce_order_itemmeta.meta_value AS Adults,
wp_postmeta.meta_value AS FirstName,
jn_postmeta_lastname.meta_value AS LastName,
jn_woocommerce_order_itemmeta_location.meta_value AS Location,
jn_woocommerce_order_itemmeta_date.meta_value AS ShowDate,
(SELECT
GROUP_CONCAT(wp_comments.comment_content)
FROM
wp_comments
WHERE
wp_comments.comment_content NOT LIKE '%status%'
AND wp_comments.comment_post_ID = wp_posts.ID) Notes
FROM
wp_postmeta
LEFT JOIN
wp_postmeta AS jn_postmeta_lastname ON wp_postmeta.post_id = jn_postmeta_lastname.post_id
LEFT JOIN
wp_posts ON wp_postmeta.post_id = wp_posts.ID
LEFT JOIN
wp_woocommerce_order_items ON wp_woocommerce_order_items.order_id = wp_posts.ID
LEFT JOIN
wp_woocommerce_order_itemmeta ON wp_woocommerce_order_itemmeta.order_item_id = wp_woocommerce_order_items.order_item_id
LEFT JOIN
wp_woocommerce_order_itemmeta AS jn_woocommerce_order_itemmeta_location ON wp_woocommerce_order_itemmeta.order_item_id = jn_woocommerce_order_itemmeta_location.order_item_id
LEFT JOIN
wp_woocommerce_order_itemmeta AS jn_woocommerce_order_itemmeta_date ON wp_woocommerce_order_itemmeta.order_item_id = jn_woocommerce_order_itemmeta_date.order_item_id
LEFT JOIN
wp_comments ON wp_comments.comment_post_ID = wp_posts.ID
WHERE
1 = 1
AND (wp_postmeta.meta_key = '_billing_first_name'
AND jn_postmeta_lastname.meta_key = '_billing_last_name'
AND wp_woocommerce_order_itemmeta.meta_key = 'Adults'
AND jn_woocommerce_order_itemmeta_location.meta_key = 'Booking Type'
AND jn_woocommerce_order_itemmeta_location.meta_value LIKE "%'.$showlocation.'%"
AND jn_woocommerce_order_itemmeta_date.meta_key = 'Booking Date'
AND jn_woocommerce_order_itemmeta_date.meta_value = "'.$showdate.'"
AND wp_posts.post_status = 'wc-completed'
GROUP BY wp_posts.ID

Advanced Wordpress MySQL Query selecting products and attributes

I've been at this for the last 6 hours so I figured I'd ask here for help.
My goal is to display all products in the database on a page on the site. The products are domain names and each one has attributes that need to be displayed.
I'm pretty stumped, here's what I've got so far:
SELECT p.id, p.post_title, p.guid,
meta_price.meta_value as price,
mozrank.name as mozrank,
pa.name as pa
FROM wp_posts p
INNER JOIN wp_postmeta meta_price ON p.id=meta_price.post_id
AND meta_price.meta_key='_regular_price'
INNER JOIN wp_postmeta meta_instock ON p.id=meta_instock.post_id
AND meta_instock.meta_key='_stock_status'
INNER JOIN wp_term_relationships relationships ON p.id=relationships.object_id
INNER JOIN wp_term_taxonomy ttmozrank ON ttmozrank.taxonomy='pa_mozrank'
AND ttmozrank.term_taxonomy_id=relationships.term_taxonomy_id
INNER JOIN wp_terms mozrank ON mozrank.term_id=ttmozrank.term_id
INNER JOIN wp_term_taxonomy ttpa ON ttpa.taxonomy='pa_pa'
AND ttpa.term_taxonomy_id=relationships.term_taxonomy_id
INNER JOIN wp_terms pa ON pa.term_id=ttpa.term_id
WHERE p.post_status = 'publish'
AND post_type = 'product'
AND meta_price.meta_value<>''
AND meta_instock.meta_value = 'instock'
GROUP BY p.id
When you remove this block, MySQL outputs what I want but only for one attribute.
INNER JOIN wp_term_taxonomy ttpa ON ttpa.taxonomy='pa_pa'
AND ttpa.term_taxonomy_id=relationships.term_taxonomy_id
INNER JOIN wp_terms pa ON pa.term_id=ttpa.term_id
There are a few attributes I want to show: item-number, pa, da, mozrank, backlinks, referring-domains, tf, cf.
Help would be appreciated greatly :)
Edit: Table Structure
wp_terms
term_id
name
wp_term_taxonomy
term_taxonomy_id
term_id
taxonomy
wp_term_relationships
object_id
term_taxonomy_id
wp_postmeta
post_id
meta_id
meta_key
meta_value
I suggest you change your INNER JOINs to LEFT JOINs. INNER JOIN will remove rows if nothing matches in the table to the left side of the join.
You may also want to recast your ON clauses with parentheses, as follows:
INNER JOIN wp_term_taxonomy ttpa
ON ( ttpa.taxonomy='pa_pa'
AND ttpa.term_taxonomy_id=relationships.term_taxonomy_id)
edit
What purpose does the GROUP BY clause serve? You are using an evil confusing nonstandard MySQL extension to GROUP BY. Read this and understand it, or get rid of GROUP BY. http://dev.mysql.com/doc/refman/5.0/en/group-by-extensions.html Seriously.
There are three things going on in your query, it seems. We need to break this stuff down carefully if we are to have any chance of troubleshooting this thing. Let's use the Structured in Structured Query Language to get this working correctly.
First, you are trying to get a resultset containing particular posts (in your case, items for sale).
SELECT p.id, p.post_title, p.guid
FROM wp_posts p
WHERE p.post_status = 'publish'
AND post_type = 'product'
Does this query yield an appropriate list of items? It may contain some unpriced items or other such things, but it should have, at least, all the items you need in your list.
Second, you are trying to retrieve and display taxonomy information (categories, keywords, etc) for your product posts. Here's a query that fetches that stuff, I think (I don't understand this part of your application as well as you do). I think there are two areas of taxonomy you're trying to pull out. This is the typical WordPress taxonomy lookup hairball. One of them is this:
SELECT tr.object_id AS id,
t.name AS mozrank
FROM wp_term_relationships AS tr
INNER JOIN wp_term_taxonomy AS x
ON (x.taxonomy='pa_mozrank'
AND x.term_taxonomy_id=tr.term_taxonomy_id)
INNER JOIN wp_terms AS t
ON t.term_id=x.term_id
Test this query. It should give a row for every post that's classified in the 'pa_mozrank' taxonomy showing the post id and the mozrank value in that taxonomy. Make sure this query works. If not, figure it out. Do not proceed until you understand this one and have it working.
Ditto ditto for the the query to fetch the value from the pa_pa hierarchy.
SELECT tr.object_id AS id,
t.name AS pa
FROM wp_term_relationships AS tr
INNER JOIN wp_term_taxonomy AS x
ON (x.taxonomy='pa_pa'
AND x.term_taxonomy_id=tr.term_taxonomy_id)
INNER JOIN wp_terms AS t
ON t.term_id=x.term_id
Third, you're retrieving particular attributes from post_meta. We need something similar for posts and prices, and posts and stock status. Again, write these queries and debug them individually. Here's for price.
SELECT post_id AS id, meta_value AS price
FROM wp_postmeta
WHERE meta_key = `_regular_price'
Here's for stock status.
SELECT post_id AS id, meta_value AS stockstatus
FROM wp_postmeta
WHERE meta_key = `_stock_status'
Good: we have five debugged subqueries. Each is indexed on id.
list of published product posts
list of all posts with their pa_mozrank classifications.
list of all posts with their pa_pa classifications.
price.
stocking status.
Now we need to join all this stuff together. Here's the general outline of our final query. Presumably you can see how this relates to your original query.
SELECT whatever
FROM wp_posts AS p
LEFT JOIN (mozranks) AS mo ON p.id = mo.id
LEFT JOIN (pas) AS pa ON p.id = pa.id
LEFT JOIN (prices) AS pr ON p.id = pr.id
LEFT JOIN (stockstatus) AS ss ON p.id = ss.id
WHERE p.post_status = 'publish'
AND p.post_type = 'product'
AND pr.price <> ''
AND ss.stockstatus = 'instock'
We're using LEFT JOIN here because we still want stuff from the wp_posts table even if it is missing some or all of the attributes.
Finally, putting it all together, we get rather a gigantic query. But we get a query in which all the parts of been unit tested. So, we don't have to smack our foreheads and say WTF? WTF? at this stage of creating the query.
SELECT whatever
FROM wp_posts AS p
LEFT JOIN (
SELECT tr.object_id AS id,
t.name AS mozrank
FROM wp_term_relationships AS tr
INNER JOIN wp_term_taxonomy AS x
ON (x.taxonomy='pa_mozrank'
AND x.term_taxonomy_id=tr.term_taxonomy_id)
INNER JOIN wp_terms AS t
ON t.term_id=x.term_id
) AS mo ON p.id = mo.id
LEFT JOIN (
SELECT tr.object_id AS id,
t.name AS pa
FROM wp_term_relationships AS tr
INNER JOIN wp_term_taxonomy AS x
ON (x.taxonomy='pa_pa'
AND x.term_taxonomy_id=tr.term_taxonomy_id)
INNER JOIN wp_terms AS t
ON t.term_id=x.term_id
) AS pa ON p.id = pa.id
LEFT JOIN (
SELECT post_id AS id, meta_value AS price
FROM wp_postmeta
WHERE meta_key = `_regular_price'
) AS pr ON p.id = pr.id
LEFT JOIN (
SELECT post_id AS id, meta_value AS stockstatus
FROM wp_postmeta
WHERE meta_key = `_stock_status'
) AS ss ON p.id = ss.id
WHERE p.post_status = 'publish'
AND p.post_type = 'product'
AND pr.price <> ''
AND ss.stockstatus = 'instock'
That's a long query, but you can see how it's put together pretty easily, and you can debug the parts one by one.
Query optimizers are designed to make this stuff as efficient as it can be, so you don't have to worry about that, unless you have, let's say, millions of items for sale, in which case you're probably amazon.com anyway.
If you were an enterprise developer doing this for a big company, you might use SQL views for the subqueries. (If you were on Oracle or PostgreSQL, you could employ WITH clauses in your queries.) You could even do this in WordPress, but you'd probably want to write a plugin that created and deleted them on activation and deactivation. Just using large SQL queries might be easier.
You have too much joins it will increase your load time.. Please do it like i did it..
SELECT
p1.ID as id,
p1.post_title as title,
p1.post_content as description,
p1.guid as link,
(CASE WHEN pm1.meta_key = '_thumbnail_id' then p2.guid ELSE NULL END) as image_​​link,
(CASE WHEN pm1.meta_key = '_stock_status' then pm1.meta_value ELSE NULL END) as availability,
(CASE WHEN pm1.meta_key = '_sale_price' then pm1.meta_value ELSE NULL END) as sales_price,
(CASE WHEN pm1.meta_key = '_price' then pm1.meta_value ELSE NULL END) as price,
(CASE WHEN pm1.meta_key = '_regular_price' then pm1.meta_value ELSE NULL END) as regular_price
FROM
wp_posts p1
LEFT JOIN
wp_postmeta pm1
ON (
pm1.post_id = p1.ID
)
LEFT JOIN
wp_posts p2
ON (
pm1.post_id = p2.ID
)
WHERE
p1.post_type IN ('product','product_variation')
AND
p1.post_status = 'publish'
GROUP BY p1.ID

How do I filter tags down to specific categories?

I have this working query here that will retrieve tags used in the last 60 days.
$term_ids = $wpdb->get_results("
SELECT DISTINCT wp_term_taxonomy.term_id, wp_terms.name
FROM wp_term_taxonomy
INNER JOIN wp_term_relationships ON wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id
INNER JOIN wp_posts ON wp_posts.ID = wp_term_relationships.object_id
INNER JOIN wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id
WHERE wp_term_taxonomy.taxonomy = 'post_tag' AND DATE_SUB(CURDATE(), $show_tags_in_days) <= $wpdb->posts.post_date", ARRAY_A);
What I need to modify this to is tags used in the last 60 days AND in a specific Wordpress category. This will be used on a category page of Wordpress. I've been fiddling with this for awhile and I think I've just got myself all confused. Is there a way to do this with another join or should I run two separate queries?
I managed to figure it out. Here is the query I came up with.
SELECT DISTINCT wp_term_taxonomy.term_id, wp_terms.name FROM wp_terms
INNER JOIN wp_term_relationships ON wp_term_relationships.term_taxonomy_id=wp_terms.term_ID
INNER JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
INNER JOIN wp_posts ON wp_posts.ID=wp_term_relationships.object_id
WHERE wp_term_taxonomy.taxonomy = 'post_tag' AND wp_posts.ID IN (
SELECT wp_posts.ID FROM wp_terms
INNER JOIN wp_term_relationships ON wp_term_relationships.term_taxonomy_id=wp_terms.term_ID
INNER JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
INNER JOIN wp_posts ON wp_posts.ID=wp_term_relationships.object_id
WHERE wp_term_taxonomy.taxonomy = 'category' AND wp_terms.term_id=$cur_cat_id) LIMIT 10
Here is a more in-depth explanation: http://www.ohthecode.com/wordpress/most-used-tags-in-wordpress/
This query retrieves only taxonomy IDs. It is likely that you are using the $term_ids variable in another query to retrieve the posts that have both a tag from the list in the $term_ids variable and are in the category. In other words, find the place where you are actually retrieving posts and pass in both the $term_ids and the category id you are interested in.
However, since you say that you are doing this on a category template page (say category-mycategory.php), you may not need to do anything additional at all since the category should be passed in automatically.