MySQL: Using JOIN statement in a subqery [duplicate] - mysql

This question already has answers here:
Referencing a query result alias in a subquery
(3 answers)
Closed 2 years ago.
Joins can be formulated in an explicit syntax ([INNER|LEFT|OUTER|..] JOIN... ON...) or specifying the conditions in the WHERE statement.
How can I refer to a table called in the external FROM statement and JOIN it in the subquery?
In this case I'm referring to the table with the alias p
SELECT
p.id,
p.post_title,
(SELECT
GROUP_CONCAT(DISTINCT wp_terms.name
SEPARATOR ',')
FROM
p
JOIN
wp_term_relationships ON (p.id = wp_term_relationships.object_id)
LEFT JOIN
wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
LEFT JOIN
wp_terms ON (wp_terms.term_id = wp_term_taxonomy.term_id)
AND wp_term_taxonomy.taxonomy IN ('post_tag' , 'category'))
FROM
`post_senza_revisioni` p
WHERE
p.post_type = 'post'
AND p.post_status = 'publish'
AND p.post_parent = 0
GROUP BY id , post_title

I'm pretty sure you want a correlated subquery:
SELECT p.id, p.post_title,
(SELECT GROUP_CONCAT(DISTINCT wp_terms.nameSEPARATOR ',')
FROM wp_term_relationships tr
wp_term_taxonomy tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id LEFT JOIN
wp_terms t
ON t.term_id = tt.term_id AND
tt.taxonomy IN ('post_tag' , 'category'))
WHERE p.id = r.object_id
)
FROM `post_senza_revisioni` p
WHERE p.post_type = 'post' AND
p.post_status = 'publish' AND
p.post_parent = 0;
I doubt the GROUP BY is needed in the outer query, so I removed it. If you do have duplicate id values in the p table, then you can add it back in -- although that suggests that id is a really bad name for the column.

Without knowing the data you, I think you should be able to use the sub query in the FROM clause, join on the ID and then just select * or your desired columns from the sub query.
SELECT
p.id,
p.post_title,
sub.*
FROM
`post_senza_revisioni` p
JOIN (SELECT
GROUP_CONCAT(DISTINCT wp_terms.name
SEPARATOR ',')
FROM
p
JOIN
wp_term_relationships ON (p.id = wp_term_relationships.object_id)
LEFT JOIN
wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
LEFT JOIN
wp_terms ON (wp_terms.term_id = wp_term_taxonomy.term_id)
AND wp_term_taxonomy.taxonomy IN ('post_tag' , 'category')
) sub
ON p.id = sub.id
WHERE
p.post_type = 'post'
AND p.post_status = 'publish'
AND p.post_parent = 0
GROUP BY id , post_title

Related

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'

Based on the following MYSQL query how can I write an UPDATE statement to update a value?

I'm using the following SQL query to get the records I need from a Wordpress database.
SELECT p.id, p.post_title, m.meta_key, m.meta_value, t.slug
FROM wp_posts p
INNER JOIN wp_postmeta m ON p.id=m.post_id
AND m.meta_key='_subscription_sign_up_fee'
INNER JOIN wp_term_relationships AS tr ON p.id = tr.object_id
INNER JOIN wp_term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN wp_terms AS t ON tt.term_id = t.term_id
WHERE t.slug = 'bundle'
This pulls the correct records. My issue is that I need to increase the value of the _subscription_sign_up_fee by 100.
I've tried the following
update wp_postmeta
set wp_postmeta.meta_value = wp_postmeta.meta_value + 100
INNER JOIN wp_postmeta m ON wp_posts.id=m.post_id
AND m.meta_key='_subscription_sign_up_fee'
INNER JOIN wp_term_relationships AS tr ON wp_posts.id = tr.object_id
INNER JOIN wp_term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN wp_terms AS t ON tt.term_id = t.term_id
WHERE t.slug = 'bundle'
and get an error saying that 'Column 'meta_value' in field list is ambiguous '
I'm pretty sure I'm not understanding the aliases. Can someone point me in the right direction?
The correct syntax for MySQL UPDATE JOINs is to have SET at the end. You also have some problems in that you're joining wp_postmeta twice, but lost the join with wp_posts.
Something like this should work;
UPDATE wp_postmeta m
JOIN wp_posts
ON wp_posts.id = m.post_id AND m.meta_key = '_subscription_sign_up_fee'
JOIN wp_term_relationships AS tr
ON wp_posts.id = tr.object_id
JOIN wp_term_taxonomy AS tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id
JOIN wp_terms AS t
ON tt.term_id = t.term_id
SET m.meta_value = m.meta_value + 100
WHERE t.slug = 'bundle'
...and always remember to back up your data before running potentially destructive operations from random people on the Internet :)

Get Wordpress posts that match 2 different categories via custom SQL statement

I'm looking to write a custom SQL statement that will pull published posts from a Wordpress DB that match 2 different categories.
Category 1 (Static) = "Website-1"
Category 2 (Dynamic) = "News", "Tips", "Recreation", etc.
This is a little out of my realm so any help would be greatly appreciated.This is what I have so far:
select p.* from wp_terms wt
join wp_term_taxonomy t on wt.term_id = t.term_id
join wp_term_relationships wpr on wpr.term_taxonomy_id = t.term_taxonomy_id
join wp_posts p on p.id = wpr.object_id
where
t.taxonomy = 'category' and
wt.name = 'Website-1' and
p.post_status = 'publish'
group by p.id
order by p.post_date desc
limit 10
It will pull the first category no problem but I need it to match on 2 categories.
Any insight would be greatly appreciated.
Thanks!
The solution I came up with:
select p.* from wp_posts p
join wp_term_relationships tr on p.id = tr.object_id
join wp_term_taxonomy tt on tt.term_taxonomy_id = tr.term_taxonomy_id
join wp_terms t on t.term_id = tt.term_id
where p.id in
(select tr2.object_id from wp_term_relationships tr2
join wp_term_taxonomy tt2 on tt2.term_taxonomy_id = tr2.term_taxonomy_id
join wp_terms t2 on t2.term_id = tt2.term_id
where
tt2.taxonomy = 'category' and
t2.name in ('Website-1') and
p.id = tr2.object_id
) and
p.post_status = 'publish' and
tt.taxonomy = 'category' and
t.name in ('News')
group by p.id
order by p.post_date desc
limit 10
I'm sure there's a better way to write this query since it's pretty messy but it works for now.
Try having instead of where after group by. I would add this as question / comment but I don't have enough points... what happens if you switch the order of the categories?

Select Post with the term id

I am having a situation where i need to select a post but with where condition as shown :-
Post with both the selected terms at once.
I have tried :-
SELECT p.ID, p.post_title FROM wp_posts p
LEFT JOIN `wp_term_relationships` t
ON p.ID = t.object_id
LEFT JOIN `wp_term_taxonomy` tt
ON t.term_taxonomy_id = tt.term_taxonomy_id
WHERE tt.term_id =86
AND tt.term_id=39
GROUP BY t.object_id
HAVING COUNT( t.term_taxonomy_id ) =2
LIMIT 0,7
Here i want to select a post which is having the term id 86 & 39. These both ids are in same table.
What is the relationship between these tables?
This select works, but I think you can try another way, do you have the TAG instead of the code? Anyway, check this out.
SELECT
p.ID
FROM
wp_posts p
LEFT JOIN wp_term_relationships t ON (p.ID = t.object_id)
WHERE
exists (
SELECT tt.term_taxonomy_id FROM wp_term_taxonomy tt
WHERE tt.term_taxonomy_id = t.term_taxonomy_id
and tt.term_id in(86,39)
)
group by p.ID
having count(p.ID) = 2
Use the IN clause
SELECT p.ID
,p.post_title
FROM wp_posts p
LEFT JOIN 'wp_term_relationships' t ON p.ID = t.object_id
LEFT JOIN 'wp_term_taxonomy' tt ON t.term_taxonomy_id = tt.term_taxonomy_id
WHERE tt.term_id IN (86,39)
GROUP BY t.object_id
HAVING COUNT(t.term_taxonomy_id) = 2 LIMIT 0,7
You can write your where condition as follow:
WHERE tt.term_id in (86,39)

MySQL query for wordpress meta data

I need some help with a query that should return posts based on their wp-postratings score (http://wordpress.org/extend/plugins/wp-postratings/).
The user chooses a minimum rating (0 to 5 stars) and a maximum rating (0 to 5 stars) and the query should return the posts that match. I have it working where the user input for both values is above 0 but I can't seem to get my head around the 0 value. Since 0 represents unrated posts - and hence onces that have no ratings meta data - I need to select not only the posts where the rating is no more than the specified max value, but also every post that has no rating meta data.
How can I do this?? Any help will be very much appreciated!
Here's my current query:
SELECT DISTINCT p.*, (t1.meta_value+0.00) AS ratings_average, (t2.meta_value+0.00) AS ratings_users, (t3.meta_value+0.00) AS ratings_score
FROM wp_posts p
INNER JOIN wp_term_relationships tr ON (p.ID = tr.object_id)
INNER JOIN wp_term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)
INNER JOIN wp_terms t ON t.term_id = tt.term_id
LEFT JOIN wp_postmeta AS t1 ON t1.post_id = p.ID
LEFT JOIN wp_postmeta AS t2 ON t1.post_id = t2.post_id
LEFT JOIN wp_postmeta AS t3 ON t3.post_id = p.ID
WHERE t1.meta_key = 'ratings_average'
AND t2.meta_key = 'ratings_users'
AND t3.meta_key = 'ratings_score'
AND p.post_date < NOW()
AND p.post_status = 'publish'
AND (tt.taxonomy = 'post_tag' AND tt.term_id = t.term_id AND t.slug = 'liverpool')
AND ( (t1.meta_value+0.00) IS NULL OR (t1.meta_value+0.00) <= $max_stars )
ORDER BY p.post_date DESC
LIMIT 20
I had to do something similar a while back where I was running a cron job to send posts to another application that weren't already registered. The best method I found was to write a query that checked that the ID was NOT IN a query of posts with the meta key.
SELECT $wpdb->posts.ID
FROM $wpdb->posts
WHERE $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->posts.ID NOT IN (
SELECT $wpdb->posts.ID
FROM $wpdb->posts
left join $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
WHERE $wpdb->posts.post_status = 'publish'
AND $wpdb->postmeta.meta_key = 'meta_key')
I believe this should work, though I obviously haven't tested it.
SELECT DISTINCT p.*, (t1.meta_value+0.00) AS ratings_average, (t2.meta_value+0.00) AS ratings_users, (t3.meta_value+0.00) AS ratings_score
FROM wp_posts p
INNER JOIN wp_term_relationships tr ON (p.ID = tr.object_id)
INNER JOIN wp_term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)
INNER JOIN wp_terms t ON t.term_id = tt.term_id
LEFT JOIN wp_postmeta AS t1 ON t1.post_id = p.ID
LEFT JOIN wp_postmeta AS t2 ON t1.post_id = t2.post_id
LEFT JOIN wp_postmeta AS t3 ON t3.post_id = p.ID
WHERE t1.meta_key = 'ratings_average'
AND t2.meta_key = 'ratings_users'
AND t3.meta_key = 'ratings_score'
AND p.post_date < NOW()
AND p.post_status = 'publish'
AND (tt.taxonomy = 'post_tag'
AND tt.term_id = t.term_id
AND t.slug = 'liverpool')
AND (
p.ID NOT IN (
SELECT p.ID
FROM wp_posts AS p
LEFT JOIN wp_postmeta AS pm ON (pm.post_id = p.ID)
WHERE pm.meta_key = 'ratings_score'
)
OR
(t1.meta_value+0.00) <= $max_stars )
ORDER BY p.post_date DESC
LIMIT 20
Okay, this query seems to work for me. Its a bit ugly though and not too quick so if anyone has a better one feel free to improve upon it!
It selects all of the rated posts that are below the $max_stars value, then combines the table with a separate select which gets all of the non-rated posts:
(SELECT DISTINCT p.*, (t1.meta_value+0.00) AS ratings_average, (t2.meta_value+0.00) AS ratings_users, (t3.meta_value+0.00) AS ratings_score
FROM wp_posts p
INNER JOIN wp_term_relationships tr ON (p.ID = tr.object_id)
INNER JOIN wp_term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)
INNER JOIN wp_terms t ON t.term_id = tt.term_id
LEFT JOIN wp_postmeta AS t1 ON t1.post_id = p.ID
LEFT JOIN wp_postmeta AS t2 ON t2.post_id = p.ID
LEFT JOIN wp_postmeta AS t3 ON t3.post_id = p.ID
WHERE t1.meta_key = 'ratings_average'
AND t2.meta_key = 'ratings_users'
AND t3.meta_key = 'ratings_score'
AND p.post_date < NOW()
AND p.post_status = 'publish'
AND (tt.taxonomy = 'post_tag' AND tt.term_id = t.term_id AND t.slug = 'liverpool')
AND (t1.meta_value+0.00) <= $max_stars )
UNION
(SELECT DISTINCT p.*, NULL AS ratings_average, NULL AS ratings_users, NULL AS ratings_score
FROM wp_posts p
INNER JOIN wp_term_relationships tr ON (p.ID = tr.object_id)
INNER JOIN wp_term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)
INNER JOIN wp_terms t ON t.term_id = tt.term_id
LEFT JOIN wp_postmeta AS t1 ON (t1.post_id = p.ID AND t1.meta_key = 'ratings_score')
WHERE t1.post_id is null
AND p.post_date < NOW()
AND p.post_status = 'publish'
AND (tt.taxonomy = 'post_tag' AND tt.term_id = t.term_id AND t.slug = 'liverpool') )
ORDER BY post_date DESC