Calculate count of rows in MySQL query [duplicate] - mysql

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')

Related

create proper MYSQL query Wordpress

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')

mysql sum returning wrong value

Hi there so i have this problem in the following query, inside wp_wti_like_post i have number of rows with similar post_id and with value column as 1 or -1.
So let's say for post with id 727 i have only one row , so the sum should be 1, but don't know why it does return 4 and when there are two rows with 727 it does return 8 query is below:
SELECT wp_posts. * ,
SUM( wp_wti_like_post.value ) -4 AS total_sum,
wp_wti_like_post.post_id
FROM wp_posts
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 )
JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
LEFT JOIN wp_wti_like_post ON ( wp_posts.ID = wp_wti_like_post.post_id )
WHERE wp_term_taxonomy.taxonomy = 'category'
AND wp_term_taxonomy.term_id IN ('$c_cid')
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish')
GROUP BY wp_posts.ID
HAVING SUM( wp_wti_like_post.value ) > $min_like
ORDER BY wp_posts.post_date DESC
You are using joins among many tables and there may b a chance that any of them has many associations for a post_id therefore your sum is incorrect i suggest you to use a sub select for your like table and calculate sum in sub select and then join with your main query
SELECT
p.*, COALESCE(l.sum_like,0) AS total_sum,
l.post_id
FROM
wp_posts p
INNER JOIN wp_term_relationships ttr
ON (p.ID = ttr.object_id)
INNER JOIN wp_term_taxonomy tt
ON (ttr.term_taxonomy_id = tt.term_taxonomy_id)
LEFT JOIN (
SELECT post_id ,SUM(`value`) sum_like
FROM wp_wti_like_post
GROUP BY post_id
) l ON (p.ID = l.post_id)
WHERE tt.taxonomy = 'category'
AND tt.term_id IN ('21')
AND p.post_type = 'post'
AND (p.post_status = 'publish')
HAVING total_sum > 2
ORDER BY p.post_date DESC
Also note i have removed wp_postmeta join because its not used in your selection criteria and neither in your filter criteria also wp_postmeta stores different attributes for each post so i guess this table is producing more rows thats why wrong sum is calculated.
Removed -4 from query

Why Does This SQL INNER JOIN Work and This Doesn't?

I'm still pretty new to SQL, and I'm having trouble wrapping my mind around why one of these queries functions properly and one does not. This is stemming from my attempts to optimize a complex and slow query. #kalengi suggested what looks like a brilliant solution to me, but it doesn't seem to work on my site. Here are the queries.
This is the standard SQL that WordPress generates (this is working as expected):
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
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)
WHERE 1=1
AND wp_posts.post_type = 'product'
AND (wp_posts.post_status = 'publish')
AND (
(wp_postmeta.meta_key = '_visibility' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog'))
AND (mt1.meta_key = '_stock_status' AND CAST(mt1.meta_value AS CHAR) = 'instock')
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.menu_order,wp_posts.post_title asc
LIMIT 0, 10
This is the SQL after #kalengi's filter processes it to combine the multiple INNER JOINs into one (this returns 0 results):
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_postmeta AS pmta ON (wp_posts.ID = pmta.post_id)
WHERE 1=1
AND wp_posts.post_type = 'product'
AND ( wp_posts.post_status = 'publish' )
AND (
( pmta.meta_key = '_visibility' AND CAST(pmta.meta_value AS CHAR) IN ( 'visible','catalog' ) )
AND ( pmta.meta_key = '_stock_status' AND CAST(pmta.meta_value AS CHAR) = 'instock' )
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.menu_order,wp_posts.post_title asc
LIMIT 0, 10
Can anyone explain whey the second one doesn't work to me?
The two inner joins:
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)
represent two data sets (that happen to be "the same").
Given the WHERE condition, the results will be sets of two rows where the first (wp_postmeta) meets one condition:
(wp_postmeta.meta_key = '_visibility' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog'))
And the second meets a completely different condition:
(mt1.meta_key = '_stock_status' AND CAST(mt1.meta_value AS CHAR) = 'instock')
By combining everything into one INNER JOIN, you're instead looking for ONE ROW which matches both conditions. Apparently there isn't one.
If you review the "brilliant solution", you'll see that 'AND's were changed to 'OR' to preserve the semantics:
AND (
( pmta.meta_key = '_visibility' AND CAST(pmta.meta_value AS CHAR) IN ( 'visible','catalog' ) )
OR ( pmta.meta_key = '_stock_status' AND CAST(pmta.meta_value AS CHAR) = 'instock' )
)
It looks like you have a condition in your WHERE clause that is looking for two values at the same time in the pmta.meta_key and pmta.meta_value columns:
....
( pmta.meta_key = '_visibility' AND CAST(pmta.meta_value AS CHAR) IN ('visible','catalog' ) )
AND ( pmta.meta_key = '_stock_status' AND CAST(pmta.meta_value AS CHAR) = 'instock' )
....
One column cannot have two different values in the same row, so this test will return FALSE, and consequently, no rows will be returned.
If you rewrite the original query to group the join conditions into the ON clauses, you can see why your second query won't work:
SELECT
SQL_CALC_FOUND_ROWS wp_posts.ID
FROM
wp_posts
INNER JOIN wp_postmeta
ON wp_posts.ID = wp_postmeta.post_id
AND wp_postmeta.meta_key = '_visibility'
AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog')
INNER JOIN wp_postmeta AS mt1
ON wp_posts.ID = mt1.post_id
AND mt1.meta_key = '_stock_status'
AND CAST(mt1.meta_value AS CHAR) = 'instock'
WHERE
1=1
AND wp_posts.post_type = 'product'
AND wp_posts.post_status = 'publish'
GROUP BY
wp_posts.ID
ORDER BY
wp_posts.menu_order,
wp_posts.post_title asc
LIMIT 0, 10
If you want to join the table only once, try something like this:
SELECT
SQL_CALC_FOUND_ROWS wp_posts.ID
FROM
wp_posts
INNER JOIN wp_postmeta
ON wp_posts.ID = wp_postmeta.post_id
AND (
wp_postmeta.meta_key = '_visibility'
AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog')
) OR (
wp_postmeta.meta_key = '_stock_status'
AND CAST(wp_postmeta.meta_value AS CHAR) = 'instock'
)
WHERE
1=1
AND wp_posts.post_type = 'product'
AND wp_posts.post_status = 'publish'
GROUP BY
wp_posts.ID
ORDER BY
wp_posts.menu_order,
wp_posts.post_title asc
LIMIT 0, 10

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.

MySQL query condition on joined tables

I have the following MySQL Query (querying wordpress db):
SELECT wp_posts.ID, wp_posts.post_date, wp_posts.post_content, wp_posts.post_title, wp_terms.name, wp_term_taxonomy.taxonomy
FROM wp_posts
LEFT JOIN wp_term_relationships ON ( wp_term_relationships.object_id = wp_posts.ID )
LEFT JOIN wp_term_taxonomy ON ( wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
LEFT JOIN wp_terms ON ( wp_terms.term_id = wp_term_taxonomy.term_id)
WHERE 1=1
AND wp_terms.name != 'MyTagName'
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish')
ORDER BY wp_posts.post_date DESC
LIMIT 100
I am basically trying to STOP all 'wp_posts' coming back that have a tag (db table wp_terms) 'MyTagName'. But all the above seems to do is strip that tag name out from the rows returned, leaving the wp_post entry in there with the other tag entries it is tagged with.
Can anyone help me with this?
SELECT wp_posts.ID, wp_posts.post_date, wp_posts.post_content, wp_posts.post_title, wp_terms.name, wp_term_taxonomy.taxonomy
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
WHERE NOT EXISTS (
SELECT 1
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_terms.name = 'MyTagName'
)
AND wp_posts.post_type = 'post'
AND wp_posts.post_status = 'publish'
ORDER BY wp_posts.post_date DESC
LIMIT 100
The problem is that your current solution isn't checking all wp_terms that relate to the post, just the specific one. If there were 5 terms, one of which was 'MyTagName', then that single one would be discluded but the other 4 will still be joined.
Now regarding the:
AND wp_posts.post_type = 'post'
AND wp_posts.post_status = 'publish'
You don't need to put them in the big NOT EXISTS check because that post won't be picked up anyway if either of them are false.