MySQL date comparison filter - mysql

I have some SQL code that works great and returns the desired results from my Wordpress database.
However, I simply cannot get my head around how to filter dates between say:
2010-12-10 00:00:00
and
2010-12-15 00:00:00
Here is my SQL code:
$SQL_K = "SELECT SQL_CALC_FOUND_ROWS wp_posts.*
FROM wp_posts
JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1 = 1
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
AND wp_postmeta.meta_key = 'expiry_date'
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 100 ";

WHERE date_column BETWEEN STR_TO_DATE('2010-12-10', '%Y-%m-%d') AND STR_TO_DATE('2010-12-15', '%Y-%m-%d')
Like so?
EDIT: forgot a closing quote. oops
EDITv2: Adding your code with the updated query
EDITv3: little optimization
removed 1=1 comparison, uses IN() for wp_posts.post_status
SELECT SQL_CALC_FOUND_ROWS wp_posts.*
FROM wp_posts
JOIN wp_postmeta
ON (wp_posts.ID = wp_postmeta.post_id)
WHERE wp_posts.post_type = 'post'
AND (wp_posts.post_status IN ('publish','private'))
AND wp_postmeta.meta_key = 'expiry_date'
AND ___INSERT_NAME_OF_DATE_COLUMN_HERE___
BETWEEN STR_TO_DATE('2010-12-05', '%Y-%m-%d')
AND STR_TO_DATE('2010-12-15', '%Y-%m-%d')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 100

use between date1 and date2

Related

Need help optimizing query that is taking >28 seconds and eating cpu

I have a wordpress installation with a large amount of entries (posts) in the table.
I have the following query that is taking almost 30 seconds. Any ideas on how I can optimize?
I think that the cast is what is stalling here but not sure.
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_postmeta.meta_key = 'post_views_count_7_day_total'
AND ( mt1.meta_key = 'post_views_count_7_day_last_date'
AND CAST(mt1.meta_value AS SIGNED) > '1626290358' ) )
AND wp_posts.post_type = 'post'
AND ((wp_posts.post_status = 'publish'))
GROUP BY wp_posts.ID
ORDER BY CAST(wp_postmeta.meta_value AS SIGNED) DESC
LIMIT 0, 3

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

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