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.
Related
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.
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
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)
I have a MySQL DB with 2 tables.
First table:
Posts
ID
post_title
post_content
... etc
And second table with additional data:
Postmeta
ID
Post_ID (FK)
meta_key
meta_value
The data that I need is in the meta_key/value pairs. But this DB organized in the way that each row in the second table only have one piece of information.
For example (second table):
ID Post_ID meta_key meta_value
1 5 info 30
ID Post_ID meta_key meta_value
2 5 additional_info 40
ID Post_ID meta_key meta_value
3 6 info 50
ID Post_ID meta_key meta_value
4 6 additional_info 60
So if I run query
SELECT
posts.id,
posts.post_date,
posts.post_author,
posts.post_content,
posts.post_title,
postmeta.meta_id,
postmeta.meta_key,
postmeta.meta_value
FROM posts INNER JOIN postmeta ON posts.id = postmeta.post_id
WHERE posts.post_type = 'post'
I get back all data that I need but data from first table (ID/post_content etc) repeated many times.
But I only need data from first table once but all additional data from second table related to ID from the first table.
How I should filter all this stuff? May be some php loop?
You can use a mysql group_concat function like this:
select
posts.id,
posts.post_date,
posts.post_author,
posts.post_content,
posts.post_title,
group_concat(postmeta.meta_id) as metaID,
group_concat(postmeta.meta_key) as metaKey,
group_concat(postmeta.meta_value_ as metaValue
from
posts
INNER JOIN postmeta
ON posts.id = postmeta.post_id
where
posts.post_type = 'post'
group by
posts.id,
posts.post_date,
posts.post_author,
posts.post_content,
posts.post_title
The to split out the results in PHP you can easily use an explode function to form an array of the resulting information.
SELECT * FROM Posts, Postmeta
WHERE Posts.Post_id = Postmeta.Post_id
GROUP BY Posts.Post_id
Use SELECT DISTINCT instead of just SELECT
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.