Show markers within a given radius (SQL and wordpress) - php

Consider this SQL query:
SELECT * FROM
(
SELECT * FROM wp_postmeta
WHERE
(
meta_key = 'latitude' AND meta_value *1 BETWEEN 47.3641471102 AND 47.3731524898)
OR (meta_key = 'longitude' AND meta_value *1 BETWEEN 8.53253429117 AND 8.54583070883)
)
AS PostMeta, wp_posts
WHERE wp_posts.id = PostMeta.post_id order by post_id asc
It gives me all records that match either latitude between certain values OR the longitude between certain values. What I want to get is the records that match both values.
But changing the 'OR' in the query to 'AND' will give me zero results.
I think I need to do a subquery of somekind but dont know how to do it tho.
Anyone?

You really just need to split your latitude sub query up from your longitude sub query. Now that I have more time, I'll rework the query more explicitly:
SELECT
/* You're only interested in the wp_posts data, right? */
/* You don't care about the data from wp_postmeta. */
/* Only select the data you're actually going to use. */
/* Ideally you'd specify each column in wp_posts that you're */
/* going to use and ignore the rest */
p.*
FROM
wp_posts p
JOIN (SELECT post_id FROM wp_postmeta WHERE meta_key = 'latitude' AND CAST(meta_value AS DECIMAL) BETWEEN 47.3641471102 AND 47.3731524898) lat ON p.id = lat.post_id
JOIN (SELECT post_id FROM wp_postmeta WHERE meta_key = 'longitude' AND CAST(meta_value AS DECIMAL) BETWEEN 8.53253429117 AND 8.54583070883) long ON p.id = long.post_id
ORDER BY
post_id ASC
... as no single wp_postmeta record will be both a latitude and a longitude, you can't (at least, not nearly as simply as this) match them both in the same WHERE clause. So instead, create two separate calls to the wp_postmeta table, one for latitude and one for longitude, and just force them both to match (hence the INNER JOIN, rather than a LEFT JOIN)

Related

Trying to get a list of unique events from wp_posts with data from wp_postmeta

I've spent about 4 hours trying to figure out why I cannot do a group by of the post_title and left join the date data from the wp_postmeta table
The code without the group by clause, results all my events but I only want to retrieve the first instance of the event, by grouping by the post_title, which should give me the only first date in the string of classes to sign up for.
What am I doing wrong here?
SELECT posts.post_title,meta.date
FROM wp_posts posts
LEFT JOIN (
SELECT meta_value AS date,post_id FROM wp_postmeta
WHERE wp_postmeta.meta_key ='_EventStartDate'
) meta
ON posts.ID = meta.post_ID
WHERE posts.post_type='Tribe_Events' AND posts.post_status = 'publish'
GROUP BY posts.post_title
Currently meta.date is not in a GROUP BY, no math is performed on this field, and it is not part of a DISTINCT list of fields
It sounds like you want the first instance of wp_postmeta.meta_value for each wp_posts.post_title
If so, try this:
Ditch the subquery and resolve your meta.meta_key filter using COALESCE
Use the MIN function on meta.meta_value
If needed, CAST meta.meta_value as a datetime
Something like this maybe...harder to know without seeing the table structure and sample data.
SELECT posts.post_title
,MIN(CAST(meta.meta_value as DATETIME)) event_start_date
FROM wp_posts posts
LEFT JOIN wp_postmeta meta
ON posts.ID = meta.post_ID
WHERE posts.post_type ='Tribe_Events'
AND posts.post_status = 'publish'
AND COALESCE(meta.meta_key, 'UNKNOWN') ='_EventStartDate'
GROUP BY posts.post_title;
This version can cope with multiple instances of '_EventStartDate' per post_title
Not sure if this is needed but it causes no harm. Just think of it as wearing a belt and suspenders.

Mysql query ignoring the row if child row from left join table doesn't exists

Hi there so first of all , i'm not that expert in mysql queries. i have tow tables wp_posts and wp_wti_like_post and i'm doing LEFT JOIN on wp_wti_like_post ON wp_posts.ID = wp_wti_like_post.post_id and SUM(wp_wti_like_post.value) < 2 BUT if there is no rowin wp_wti_like_post with id of post from wp_posts then it doesn't show even the row from wp_posts and just ignore it , please help in this really need it.
query:
SELECT *
FROM wp_posts
LEFT JOIN wp_wti_like_post ON wp_posts.ID = wp_wti_like_post.post_id
WHERE wp_posts.post_status = 'publish'
GROUP BY wp_wti_like_post.post_id
HAVING SUM( wp_wti_like_post.value ) <2
OR SUM( wp_wti_like_post.value ) = NULL
LIMIT 0 , 200
table wp_wti_like_post
http://prntscr.com/6xixrd
table wp_posts
http://prntscr.com/6xixzp
You might need to restructure your query to as follows:
SELECT * FROM
(
SELECT WP.*, SUM(LP.value) AS `value`
FROM wp_posts WP
LEFT JOIN
(SELECT post_id FROM wp_wti_like_post WHERE post_status = 'publish') LP
ON WP.ID = LP.post_id
GROUP BY WP.ID
) T1
WHERE T1.value IS NULL
OR T1.value < 2;
The Inner-most query first fetches only wti_like_posts that have been published.
The left-join is then performed, which will give you the expected result of fetching all rows from wp_posts, even if they do not join with a record from the sub-query.
After that is performed, the GROUP statement performs the computation of SUMming the values.
The outer-most query enforces the requirement that the sum must either be less than 2 or be null.
So i sorted this out by my self and go it working in this way
at the place of
SUM( wp_wti_like_post.value ) = NULL
it should need to be
SUM( wp_wti_like_post.value ) IS NULL

Consolidate MySQL Query Result Into Single Record

I am trying to find a way to structure a SQL Query. The data I need is in two table and comprises of 3 records, but I need to return this in a way so that I can later insert it into a table as 1 record. The query will be used within PHP so I am open to using this as well. Here is what I have:
SELECT ID, meta_key, meta_value
FROM wp_posts
INNER JOIN wp_postmeta
ON wp_posts.ID = wp_postmeta.post_id
WHERE post_status = 'publish'
AND post_date >= CURDATE()
AND post_type IN ('tribe_events', 'tribe_organizer', 'tribe_venue')
AND meta_key IN ('_EventStartDate', '_EventEndDate', '_OrganizerOrganizer', '_OrganizerWebsite', '_VenueAddress', '_VenueCity', '_VenueState', '_VenueZip')
Try self-joins with individual matches, i.e. instead of using
WHERE post_type IN (val1, val2, val3)
do the following
INNER JOIN
... ON table2.post_type = val2
INNER JOIN
... ON table3.post_type = val3
etc.
WHERE table1.post_type = val1
or whatever works. You get the idea. I don't know your schema and can't give you a more specific example.

MySQL - Query Multiple values in a single column

I am currently working on a site utilizing the WP-Property plugin for Wordpress.
Basically I am attempting to display a counter next to a text search link for a particular price range.
Below is the query I am running which does the price range count perfectly fine.
$apartprice1 = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->postmeta WHERE meta_value BETWEEN 50000 AND 74999");
if (0 < $apartprice1) $apartprice1 = number_format($apartprice1);
I would however like to extend on this to display only "Apartments" which are within this particular price range.
Now bear in mind that within the meta_value column the property type values (apartments, houses, freeholds) are also stored.
Any boffins about whom can demystify this for me please?
edit: Some further elaboration below:
Table name is postmeta
meta_id post_id meta_key meta_value
348 41 property_type apartment
358 41 price 698000
So I would like to be able to do a count of a particular price range which is also based on a specific property type
This table structure makes it somewhat difficult/inefficient to do the type of multifacet searching you're looking for. To ensure that all WHERE clauses are met, you'll need to INNER JOIN the meta table to itself. This gives you a temporary data format that's bit more suitable for your query.
SELECT m1.post_id
FROM meta m1
INNER JOIN meta m2 ON m1.post_id = m2.post_id
WHERE m1.meta_key = 'price'
AND m1.meta_value
BETWEEN 50000 AND 7000000 AND m2.meta_key = 'property_type'
AND m2.meta_value = 'apartment'
Keep in mind, for every additional facet you add, you'll need to do an additional INNER JOIN. Also, if you don't have one already, I'd recommend an index on the post_id column.
To get the count, just change what's in the SELECT clause.
SELECT COUNT(*)
FROM meta m1
INNER JOIN meta m2 ON m1.post_id = m2.post_id
WHERE m1.meta_key = 'price'
AND m1.meta_value
BETWEEN 50000 AND 7000000 AND m2.meta_key = 'property_type'
AND m2.meta_value = 'apartment'
If you are looking for displaying the count for each of the property values the partments, houses, freeholds, you should add a GROUP BY property_type
SELECT property_type, COUNT(*)
FROM $wpdb->postmeta
WHERE meta_value BETWEEN 50000 AND 74999
GROUP BY property_type
Update: You have to pivot your rows into columns in order to get the data the way you described like so:
SELECT t.property_type, COUNT(t.post_id) AS 'type count'
FROM
(
SELECT t.post_id,
MAX(CASE WHEN t.meta_key = 'property_type' THEN t.meta_value END) AS property_type,
MAX(CASE WHEN t.meta_key = 'price' THEN CAST(t.meta_value AS DECIMAL) END) AS Price
FROM postmeta t
GROUP BY t.post_id
) t
WHERE t.property_type = 'apartment'
AND t.Price BETWEEN 600000 AND 700000
GROUP BY t.property_type
Note that the meta_value field is supposed to store both a string values for property types as well as numeric values for prices so I CAST it to DECIMAL in order to select it as numeric data type so that you can perform calculation on it later on. I also used MAX as an aggregate function as a work around to pivot the rows.
Here is a demo in SQL fiddle.
This what you usually encounter in such a design model which is what they called Entity–attribute–value model. You can find a lot of useful thread about this data model under the tag eav. You can also find more useful pages about this design model in the following answer

wordpress query custom fields and category

I have a query that creates a table view and then another that queries the view. The results are extremely slow.
Here is the code:
create or replace view $view_table_name as select * from wp_2_postmeta where post_id IN (
select ID FROM wp_2_posts wposts
LEFT JOIN wp_2_term_relationships ON (wposts.ID = wp_2_term_relationships.object_id)
LEFT JOIN wp_2_term_taxonomy ON (wp_2_term_relationships.term_taxonomy_id = wp_2_term_taxonomy.term_taxonomy_id)
WHERE wp_2_term_taxonomy.taxonomy = 'category'
AND wp_2_term_taxonomy.parent = $cat || wp_2_term_taxonomy.term_id = $cat
AND wposts.post_status = 'publish'
AND wposts.post_type = 'post')
The $values have been put it in for this example that queries the view table for the results.
select distinct(ID)
FROM $view_table_name wposts
LEFT JOIN wp_2_postmeta wpostmeta
ON wposts.ID = wpostmeta.post_id
WHERE post_status = 'publish'
AND ID NOT IN (SELECT post_id
FROM wp_2_postmeta
WHERE meta_key = '$var' && meta_value = '$value1')
AND ID NOT IN (SELECT post_id
FROM wp_2_postmeta
WHERE meta_key = '$var' && meta_value = '$value2')
AND ID NOT IN (SELECT post_id
FROM wp_2_postmeta
WHERE meta_key = '$var' && meta_value = '$value3')
AND postmeta.meta_key = 'pd_form'
ORDER BY CASE wpostmeta.meta_value
WHEN '$value5' THEN 1
WHEN '$value6' THEN 2
WHEN '$value7' THEN 3
WHEN '$value8' THEN 4
WHEN '$value9' THEN 5
WHEN '$value10' THEN 6
WHEN '$value11' THEN 7
WHEN '$value11' THEN 8
END;
The main problem here is a subquery in IN condition. Instead executing the subquery and then checking in the outer table for correspondences, MySQL is known to transform the query into a correlated subquery which is executed for each row in the outer table.
The usual solution is to get rid of the subquery in the IN in favour of a JOIN.
Another problem is that you use OUTER JOIN instead of inner JOIN though you do not actually need it (MySQL is usually smart enough to optimize it when it is trivial, but anyway you should express your intention more clearly).
And one more thing. Both queries seem to be dynamically generated. Beside optimizing the query itself, one should think how not to break the calling code. That may be tricky though.
Optimizing wordpress is always an interesting challenge.

Categories