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:
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:And the second meets a completely different condition:
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:
It looks like you have a condition in your
WHERE
clause that is looking for two values at the same time in thepmta.meta_key
andpmta.meta_value
columns: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:If you want to join the table only once, try something like this: