create proper MYSQL query Wordpress - mysql

Hi i have a problem to create an sql query request.
I have a working query to get published or private posts on category and a custom post-type and a meta_key 'mapcoordinates' in my wp_usermeta table on user_id.
What i try to accomplished is extending the query that I also get another meta_value from my wp_usermeta table with meta_key 'some_value'.
So I need to search on two meta_keys values (mapcoordinates , somevalue) instead off one (mapcoordinates), see working example
Maybe somebody can help me'
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID, wp_usermeta.meta_value AS user_map_coord, wp_usermeta.user_id
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_usermeta ON ( wp_posts.post_author = wp_usermeta.user_id )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (5,6))
AND wp_posts.post_type = 'ouder_type'
AND wp_usermeta.meta_key= 'mapcoordinates'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date
Above query is working.
I like to extend it in something like this.
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID, wp_usermeta.meta_value AS user_map_coord, wp_usermeta.user_id
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_usermeta ON ( wp_posts.post_author = wp_usermeta.user_id )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN ( 5,6))
AND wp_posts.post_type = 'ouder_type'
AND wp_usermeta.meta_key= 'mapcoordinates'
// this line added not working i get only one result , expecting 2 results
AND wp_usermeta.meta_key= 'somevalue'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date

You have wp_usermeta.meta_key equal to two different things at the same time, so probably shouldn't get any results. I guess what you're after is more along the lines of:
AND wp_usermeta.meta_key IN ('mapcoordinates','somevalue')

Related

Order By doesn't work with Left Join -MySQL / Wordpress

I have my query above, it retrieves the data fine but the ordering is off. I am trying to order the results by Price. Not sure if I need to add another GROUP BY param or I need to add another join. Anyone else had the same issue?
SELECT wp_posts.ID,wp_postmeta1.meta_value AS sku, wp_postmeta2.meta_value AS Price
FROM wp_posts
LEFT JOIN wp_postmeta wp_postmeta1
ON wp_postmeta1.post_id = wp_posts.ID
AND wp_postmeta1.meta_key = '_sku'
LEFT JOIN wp_postmeta wp_postmeta2
ON wp_postmeta2.post_id = wp_posts.ID
AND wp_postmeta2.meta_key = '_price'
WHERE (wp_posts.post_type = 'product'
AND wp_posts.post_status = 'publish'
AND wp_posts.post_title LIKE '%abi%')
OR (wp_posts.post_type = 'product'
AND wp_posts.post_status = 'publish'
AND wp_postmeta1.meta_value LIKE '%abi%' )
GROUP BY wp_posts.ID
ORDER BY wp_postmeta2.meta_value ASC
LIMIT 15
Using cast fixed the sorting.
ORDER BY CAST(wp_postmeta2.meta_value as unsigned) ASC

MySQL: Subquery to get value based on another value of same column

I'm querying the WordPress wp_postmeta table for the lowest meta_value of rows with the meta_key item_thickness:
SELECT min(cast(meta_value as unsigned)) FROM wp_postmeta WHERE meta_key='item_thickness'
This works great.
Question: How would I extend this query to select the same lowest item_thickness from rows with the same post_id and with meta_key='item_status' and meta_value='Raw'
The post_id forms the relationship between these rows but I don't know how to do a JOIN on the same table or the proper syntax for a sub-query
This is my latest (failing) attempt at the query:
SELECT *
FROM wp_postmeta
JOIN (
SELECT min(cast(meta_value as unsigned)), post_id FROM wp_postmeta WHERE meta_key='item_thickness'
) b
ON wp_postmeta.post_id=b.post_id
I was able to use WP_Query to build the MySQL I needed and then edit it so it would select the value I wanted.
Working query.
$wpdb->get_var( "SELECT min(cast(wp_postmeta.meta_value as unsigned)) FROM wp_postmeta INNER JOIN wp_posts ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id ) WHERE 1=1 AND ( wp_postmeta.meta_key = 'item_thickness' AND ( mt1.meta_key = 'item_status' AND CAST(mt1.meta_value AS CHAR) = 'raw' )) AND wp_posts.post_type = 'inventory' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future' OR wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending' OR wp_posts.post_status = 'private')" );

Cannot query multiple values on an Inner Join

I'm using this sql to return results based on an inner join with 3 meta values. It only seems to work with 1 AND ( ), when i add the other two it returns 0 results.
SELECT * FROM wp_posts
INNER JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
WHERE wp_posts.post_type = 'plot'
AND wp_posts.post_status = 'publish'
AND ( wp_postmeta.meta_key = 'plot_type' AND wp_postmeta.meta_value = 'Cottage' )
AND ( wp_postmeta.meta_key = 'number_of_bedrooms' AND wp_postmeta.meta_value = '2' )
AND ( wp_postmeta.meta_key = 'property' AND wp_postmeta.meta_value = '446' )
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_title ASC;
I think you meant to use OR with the other 2 (see below). The same field can't be 2 different things, which is why you get 0 results.
SELECT *
FROM wp_posts
INNER JOIN wp_postmeta
ON (wp_posts.ID = wp_postmeta.post_id)
WHERE wp_posts.post_type = 'plot'
AND wp_posts.post_status = 'publish'
AND ((wp_postmeta.meta_key = 'plot_type' AND
wp_postmeta.meta_value = 'Cottage') OR
(wp_postmeta.meta_key = 'number_of_bedrooms' AND
wp_postmeta.meta_value = '2') OR (wp_postmeta.meta_key = 'property' AND
wp_postmeta.meta_value = '446'))
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_title ASC;
edit, try below instead:
select * from wp_posts
join wp_postmeta on wp_posts.ID = wp_postmeta.post_id
where wp_posts.post_type = 'plot'
and wp_posts.post_status = 'publish'
and concat(wp_postmeta.meta_key,'|',wp_postmeta.meta_value)
in ('plot_type|Cottage',
'number_of_bedrooms|2',
'property|446');
You need to join the wp_postmeta table once for each type of value you need.
SELECT whatever, whatever
FROM wp_posts AS p
JOIN wp_postmeta AS plottype
ON (p.ID = plottype.post_id AND plottype.meta_key = 'plot_type')
JOIN wp_postmeta AS bedrooms
ON (p.ID = bedrooms.post_id AND bedrooms.meta_key = 'number_of_bedrooms')
JOIN wp_postmeta AS property
ON (p.ID = property.post_id AND property.meta_key = 'property')
WHERE wp_posts.post_type = 'plot'
AND wp_posts.post_status = 'publish'
AND plottype.meta_value = 'Cottage'
AND bedrooms.meta_value = '2'
AND property.meta_value = '466'
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_title ASC;
This wp_postmeta key/value storage is a little tricky to join to; your join criteria need to pull the appropriate key as well as the matching post ID.
It's well known that SELECT * is a bad idea in software. It's especially bad when you're joining so many tables. List the columns you need in your result set.
Notice also that you're using INNER JOIN with which JOIN is synonymous. If any of the values you're pulling from the metadata are missing, so will be the row from your result set. You may or may not be better off using LEFT JOINs (You didn't explain the purpose of the query.)
It seems as some of the structure for your conditions should be changed.
Try the following:
SELECT * FROM wp_posts
INNER JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
WHERE wp_posts.post_type = 'plot'
AND wp_posts.post_status = 'publish'
AND (
(wp_postmeta.meta_key = 'plot_type' AND wp_postmeta.meta_value = 'Cottage')
OR
(wp_postmeta.meta_key = 'number_of_bedrooms' AND wp_postmeta.meta_value = '2')
OR
(wp_postmeta.meta_key = 'property' AND wp_postmeta.meta_value = '446')
)
ORDER BY wp_posts.post_title ASC;
I managed to fix the issue using WP_Meta_Query, the SQL it produced was...
SELECT wp_posts.* FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
WHERE 1=1
AND wp_posts.post_type = 'plot'
AND (wp_posts.post_status = 'publish')
AND (
(wp_postmeta.meta_key = 'property' AND CAST(wp_postmeta.meta_value AS CHAR) = '180')
AND (mt1.meta_key = 'plot_type' AND CAST(mt1.meta_value AS CHAR) = 'Cottage')
AND (mt2.meta_key = 'number_of_bedrooms' AND CAST(mt2.meta_value AS CHAR) = '2')
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_title ASC;
Thanks to everyone for the help :)

Inner JOIN missing row

First I would like to mention I have limited skills when it comes to MYSQL an JOIN. However this is what I have and what I like to achieve:
I have the default WordPress tables and like to get a result with post_name, title, status and the meta_value from a certain meta key.
This is what I have:
SELECT
wp_posts.ID, wp_posts.post_name, wp_posts.post_title, wp_posts.post_status, wp_postmeta.meta_value
FROM wp_posts
INNER JOIN
wp_term_relationships ON ( wp_posts.ID = wp_term_relationships.object_id )
INNER JOIN
wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
WHERE (
wp_term_relationships.term_taxonomy_id
IN ( 1, 2, 3 )
)
AND wp_posts.post_type = 'my_post_type'
AND (
wp_posts.post_status
IN (
'my_status_1', 'my_status_2'
)
)
AND wp_postmeta.meta_key = 'my_meta_key'
GROUP BY wp_posts.ID
ORDER BY wp_posts.ID ASC
Everything works as expected when each post has a postmeta of 'my_meta_key'. But if the 'my_meta_key' is missing the post is not in the result.
I guess it' caused by the second INNER JOIN but as mentioned I have no idea what I should it replace it with.
I'm sure it's something simple
Move the AND wp_postmeta.meta_key = 'my_meta_key' to
INNER JOIN
wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
Like this and change the INNER for a LEFT
LEFT JOIN
wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id
AND wp_postmeta.meta_key = 'my_meta_key')
If you put your condition in the "Where Clause" The Left join will be "overwritten".
And I will add an advice. Dont use parenthesis when you dont really need it to keep your code easy to read.
The following returns
all records from WP_Posts
only those records with WP_TERM_RELATIONSHIPS
only those records in wp_postmeta which a matching record in wp_posts.
*
SELECT wp_posts.ID, wp_posts.post_name, wp_posts.post_title,
wp_posts.post_status, wp_postmeta.meta_value
FROM wp_posts
LEFT JOIN wp_term_relationships
ON wp_posts.ID = wp_term_relationships.object_id
LEFT JOIN wp_postmeta
ON wp_posts.ID = wp_postmeta.post_id
WHERE wp_term_relationships.term_taxonomy_id IN ( 1, 2, 3 )
AND wp_posts.post_type = 'my_post_type'
AND wp_posts.post_statusIN ('my_status_1', 'my_status_2')
AND (wp_postmeta.meta_key = 'my_meta_key' or wp_postmeta.meta_key is null)
GROUP BY wp_posts.ID
ORDER BY wp_posts.ID ASC
you need the is null otherwise records in wp_posts without wp_postmeta data will be excluded.
Change the INNER JOIN on the wp_postmeta table to a LEFT JOIN:
LEFT JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
And move the WHERE filter for the wp_postmeta to the JOIN condition.
So your query will be:
SELECT wp_posts.ID, wp_posts.post_name, wp_posts.post_title, wp_posts.post_status, wp_postmeta.meta_value
FROM wp_posts
INNER JOIN wp_term_relationships
ON ( wp_posts.ID = wp_term_relationships.object_id )
LEFT JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
AND wp_postmeta.meta_key = 'my_meta_key'
WHERE wp_term_relationships.term_taxonomy_id IN ( 1, 2, 3 )
AND wp_posts.post_type = 'my_post_type'
AND wp_posts.post_status IN ('my_status_1', 'my_status_2')
GROUP BY wp_posts.ID
ORDER BY wp_posts.ID ASC
The INNER JOIN syntax will only return rows that match in both tables. So if you do not have a matching row, you will not get any result. By changing that to a LEFT JOIN, you will return all rows even if there is not a matching row in the wp_postmeta table. If the row does not exist, then the values from the wp_postmeta table will be null.

Calculate count of rows in MySQL query [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
COUNT() and DISTINCT can i use together?
I have this sql statement:
SELECT * FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE ( wp_term_relationships.term_taxonomy_id IN (4,3) )
AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'published')
and I get two rows with the same ID => expected
adding GROUP BY wp_posts.ID will reduce the count of rows to one
Now I would like to get the number of rows with and SQL query
SELECT COUNT(*) AS cnt FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE ( wp_term_relationships.term_taxonomy_id IN (4,3) )
AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'published')
GROUP BY wp_posts.ID
I'll get as result "2" instead of "1", even with the "GROUP BY".
What is the correct statement to get the numbers of rows from the first statement?
Try this:
SELECT count(DISTINCT wp_posts.ID) as cnt FROM wp_posts INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE ( wp_term_relationships.term_taxonomy_id IN (4,3) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'published')
This will give you the count of unique IDs in result rows.
Since the first query displays 2 rows, the second query should return 2, and it does. This is working as it should.
Having that GROUP BY there makes no real logical sense.
A simple fix would be to use your original sql as a subselect and do the count based on that:-
SELECT COUNT(*) AS cnt
FROM (SELECT wp_posts.ID
FROM wp_posts
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE ( wp_term_relationships.term_taxonomy_id IN (4,3) )
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'published')
GROUP BY wp_posts.ID) Sub1
Or the folowing might be OK, depending on the relationships between the tables (and so how unique wp_posts.ID is).
SELECT COUNT(DISTINCT wp_posts.ID)
FROM wp_posts
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE ( wp_term_relationships.term_taxonomy_id IN (4,3) )
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'published')