MySQL and PHP: Inner join and result - php

Here is a mysql request:
$requete1 = mysql_query("
SELECT a.post_id, e.meta_value
FROM wp_postmeta as b
INNER JOIN wp_postmeta AS a ON b.post_id = a.post_id
INNER JOIN wp_postmeta AS d ON b.post_id = d.post_id
INNER JOIN wp_postmeta AS e ON b.post_id = e.post_id
WHERE b.meta_key = '_show_hide_sales'
AND b.meta_value = '1'
AND d.meta_key = '_sold_sales'
AND d.meta_value != '3'
AND e.meta_key = '_sales_sort_number'
ORDER BY CAST(e.meta_value as UNSIGNED INTEGER) DESC
LIMIT ".($from-1).", ".($range+1)
);
while($resultat1 = mysql_fetch_array($requete1))
{
$res2= $resultat1['post_id']; // this one is ok
$res3= $resultat1['meta_value']; // this one is ambiguous
};
The search on the post_id ($res2) is ok as it is unambiguous.
But there are three possible meta_keys here:
The one that is related to "_show_hide_sales".
The one that is related to "_sold_sales".
The one that is related to "_sales_sort_number".
But how can I get the meta_value ($res3) that is related to the "_sales_sort_number" meta_key?
My SELECT clearly indicates that I want to retrieve the e.meta_value which should be associated to the "_sales_sort_number" meta_key but it doesn't seem to work.
Thank you for your guidance.

Related

MYSQL Query very slow when using ORDER BY datetime

I have the following query which runs on a social network. The query fetches posts (like Facebook posts) from a database.
SELECT P.*,
P.id_post id_p,
PM.meta_content video_title,
PM2.meta_content video_views,
PM3.meta_content racebooking_views,
Greatest(P.creation_date, Coalesce(Max(C.date), P.creation_date)) AS
last_activity,
P.creation_date creation_date,
(SELECT Count(*)
FROM likes
WHERE post_id = P.id_post
AND post_type = 'P')
likes_count,
(SELECT Count(*)
FROM likes L
WHERE post_id = P.id_post
AND post_type = 'P'
AND L.id_profile = 2796)
do_i_like
FROM posts P
LEFT JOIN comments C
ON P.id_post = C.post_id
AND C.post_type = 'P'
AND C.id_profile != P.id_profile
LEFT JOIN post_meta PM
ON PM.id_post = P.id_post
AND PM.meta_type = 'T'
LEFT JOIN post_meta PM2
ON PM2.id_post = P.id_post
AND PM2.meta_type = 'V'
LEFT JOIN post_meta PM3
ON PM3.id_post = P.id_post
AND PM3.meta_type = 'W'
GROUP BY P.id_post
ORDER BY last_activity DESC
LIMIT 41, 10
Each post may have or may not have comments.
I want the query to fetch the post with the most recent activity first.
So, if the post has a comment, i take the date of the latest comment. If the post does not have a comment, i take the creation date of the post.
The job is done by Greatest(P.creation_date, Coalesce(Max(C.date), P.creation_date)) which picks up the greates value between the comments dates (if comments exist) and the post creation date.
Then, the ORDER BY last_activity DESC does the sorting job.
PROBLEM
The query is really slow. It takes 8 seconds to run. The posts table has 8K rows and the comments table has 8K rows.
What i don't understand is that if I replace the ORDER BY clause with this ORDER BY P.id_post it takes 0.5 seconds to run. But if I replace the ORDER BY clause with ORDER BY P.creation_date again it takes 8 seconds. It seems that it doesn't like dates...
Additional infos
posts table has an index on creation_date.
comments table has an index on date
server runs LAMP on CentOS Linux 6.6
I tried other solutions on SO like this one but they didn't work
How can i fix this query to run faster?
The correlated subqueries in the select clause are probably killing you. Instead, join to a subquery which computes likes statistics:
SELECT P.*,
P.id_post id_p,
PM.meta_content video_title,
PM2.meta_content video_views,
PM3.meta_content racebooking_views,
GREATEST(P.creation_date, COALESCE(MAX(C.date), P.creation_date)) AS last_activity,
P.creation_date creation_date,
t.likes_count,
t.do_i_like
FROM posts P
LEFT JOIN
(
SELECT
post_id,
SUM(CASE WHEN post_type = 'P' THEN 1 ELSE 0 END) AS likes_count,
SUM(CASE WHEN post_type = 'P' AND L.id_profile = 2796
THEN 1 ELSE 0 END) AS do_i_like
FROM likes
GROUP BY post_id
) t
ON t.post_id = P.id_post
LEFT JOIN comments C
ON P.id_post = C.post_id AND
C.post_type = 'P' AND
C.id_profile != P.id_profile
LEFT JOIN post_meta PM
ON PM.id_post = P.id_post AND
PM.meta_type = 'T'
LEFT JOIN post_meta PM2
ON PM2.id_post = P.id_post AND
PM2.meta_type = 'V'
LEFT JOIN post_meta PM3
ON PM3.id_post = P.id_post AND
PM3.meta_type = 'W'
ORDER BY
last_activity DESC
LIMIT 41, 10
Also after editing your query I do not see a reason to be using GROUP BY in the outer query, so I removed it. And you should be using indices where appropriate, though my hunch is that my suggestion alone should give a noticeable performance boost.
There is a MAX(C.Date) that would require a group by clause, however it too could be substituted for a subquery I believe:
SELECT P.*,
P.id_post id_p,
PM.meta_content video_title,
PM2.meta_content video_views,
PM3.meta_content racebooking_views,
GREATEST(P.creation_date, COALESCE(max_c_date, P.creation_date)) AS last_activity,
P.creation_date creation_date,
t.likes_count,
t.do_i_like
FROM posts P
LEFT JOIN
(
SELECT
post_id,
SUM(CASE WHEN post_type = 'P' THEN 1 ELSE 0 END) AS likes_count,
SUM(CASE WHEN post_type = 'P' AND L.id_profile = 2796
THEN 1 ELSE 0 END) AS do_i_like
FROM likes
GROUP BY post_id
) t
ON t.post_id = P.id_post
LEFT JOIN (
SELECT
comments.post_id,
MAX(comments.date) max_c_date
FROM comments
inner join posts ON comments.post_id = posts.id_post
where comments.post_type = 'P' AND
comments.id_profile != posts.id_profile
GROUP BY comments.post_id
) C
ON P.id_post = C.post_id AND
LEFT JOIN post_meta PM
ON PM.id_post = P.id_post AND
PM.meta_type = 'T'
LEFT JOIN post_meta PM2
ON PM2.id_post = P.id_post AND
PM2.meta_type = 'V'
LEFT JOIN post_meta PM3
ON PM3.id_post = P.id_post AND
PM3.meta_type = 'W'
ORDER BY
last_activity DESC
LIMIT 41, 10

Return the count of posts where meta value is equal to

I've created a custom field by using the Advanced Custom Fields plugin. This field is called status and by default is equal upcoming and then it will be changed to either correct or wrong later.
I'm then trying to query all the posts where the status meta value is equal to either correct or wrong. However even though i've set this in the below Query it still return the count of all posts. I've double checked and counted how many posts there are equal to correct or wrong and still i get the wrong count. What am i doing wrong?
SELECT count(DISTINCT posts.ID) as count, AVG(odds.meta_value) as ave
FROM $wpdb->posts posts
LEFT JOIN $wpdb->postmeta stat
ON posts.ID = stat.post_id
AND stat.meta_key = 'status'
LEFT JOIN $wpdb->postmeta odds
ON posts.ID = odds.post_id
AND odds.meta_key = 'odds'
LEFT JOIN $wpdb->term_relationships tr ON posts.ID = tr.object_id
LEFT JOIN $wpdb->term_taxonomy t ON tr.term_taxonomy_id = t.term_taxonomy_id
WHERE stat.meta_value = 'wrong'
OR stat.meta_value = 'correct'
AND posts.post_status = 'publish'
AND t.taxonomy = 'category'
AND t.term_id = 4
OR t.term_id = 5
OR t.term_id = 6
You should use brackets to group together what should be together:
SELECT count(DISTINCT posts.ID) as count, AVG(odds.meta_value) as ave
FROM $wpdb->posts posts
LEFT JOIN $wpdb->postmeta stat
ON posts.ID = stat.post_id
AND stat.meta_key = 'status'
LEFT JOIN $wpdb->postmeta odds
ON posts.ID = odds.post_id
AND odds.meta_key = 'odds'
LEFT JOIN $wpdb->term_relationships tr
ON posts.ID = tr.object_id
LEFT JOIN $wpdb->term_taxonomy t
ON tr.term_taxonomy_id = t.term_taxonomy_id
WHERE (stat.meta_value = 'wrong'
OR stat.meta_value = 'correct')
AND posts.post_status = 'publish'
AND t.taxonomy = 'category'
AND (t.term_id = 4
OR t.term_id = 5
OR t.term_id = 6)

mySQL: selecting based on several keys in key/value table

I'm using Wordpress and trying to select values from one of my own tables that correspond to values in the native wp_postmeta table.
My table is called "wellwishertable" and I would like to find all the ID's (so I can count them) from the wellwisher table where...
1) The wellwishertable 'associatedID' field is in wp_postmeta post_id
2) The wellwishertable 'associatedAuthorID' is the same as a $userID variable
3) The wellwishertable 'permission' is pending
4) The wp_postmeta meta_key 'status' is NOT equal to meta_value 'open'
5) The wp_postmeta meta_key 'freeze' is NOT equal to meta_value 'frozen'
I've got this far...
"SELECT DISTINCT wellwisher.ID FROM wellwishertable wellwisher
INNER JOIN wp_postmeta ON (wellwisher.associatedID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_postmeta.post_id = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_postmeta.post_id = mt2.post_id)
WHERE wellwisher.associatedAuthorID=".$userID."
AND wellwisher.permission ='pending'
AND ( (mt1.meta_key = 'status' AND mt1.meta_value != 'open') AND
(mt2.meta_key = 'freeze' AND mt2.meta_value != 'frozen') );
This seems to be 'nearly' working except it doesn't count records that don't have a "freeze" meta_key in the wp_postmeta table. I want it to count any record that isn't "frozen" regardless of whether it exists or not (as long as 'status' isn't 'open').
Could someone point me in the right direction?
Use LEFT JOIN instead of INNER JOIN on mt2, as INNER JOIN will only return results that have an entry there.
In order to avoid requiring mt2.meta_key to always have to equal freeze, move that condition up to the ON clause in your join.
You could also consider using COUNT directly in your query rather than figuring it out later:
"SELECT COUNT(DISTINCT wellwisher.ID) FROM wellwishertable wellwisher
INNER JOIN wp_postmeta ON (wellwisher.associatedID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_postmeta.post_id = mt1.post_id)
LEFT JOIN wp_postmeta AS mt2 ON (wp_postmeta.post_id = mt2.post_id)
AND mt2.meta_key = 'freeze'
WHERE wellwisher.associatedAuthorID=".$userID."
AND wellwisher.permission ='pending'
AND ( (mt1.meta_key = 'status' AND mt1.meta_value != 'open') AND
(mt2.meta_value != 'frozen') );
IMPORTANT:
Dumping your $userID directly into your query string could be a big security issue. Please consider using parameterized queries.

Select rows as columns for wordpress post meta

WordPress's wp_postmeta table has all the additional fields for a post but they are in rows so it's easy to add more.
However, now I want to query for all the fields of all the posts lets say, I obviously want those fields in a column and not a row.
This is my query that I am running
SELECT p.post_title,
m.meta_value,
m.meta_key
FROM wp_posts p
JOIN wp_postmeta m
ON p.id = m.post_id
WHERE p.id = 72697;
This will give me all the meta_values and their respective meta keys as columns. But I need the meta keys values as columns and meta values as rows
For example a meta_key could be additional_description and it's value could be What's up
So I need something like this
SELECT p.post_title, additional_description
FROM wp_posts p
JOIN wp_postmeta m
ON p.id = m.post_id
WHERE p.id = 72697;
I need it as a column. I also need all of the posts and not a specific one, but whenever I remove the where it just doesn't query (I have lots of posts, that could be an issue).
Here is some sample data and how I want the results to show up
wp_postmeta table
meta_key post_id meta_key meta_value
1 5 total_related 5
2 5 updated 0
3 5 cricket 1
4 8 total_related 8
5 8 updated 1
6 8 cricket 0
wp_post table
id post_title other things I dont care about
5 This is awesome
8 This is more awesome
wp_post id is related to post_id on wp_postmeta table
Result wanted
post_title total_related updated cricket
This is awesome 5 0 1
This is more awesome 8 1 0
What about something like this?
SELECT p.post_title, m1.meta_value as 'total_related', m2.meta_value as 'updated', m3.meta_value as 'cricket'
FROM wp_posts p
LEFT JOIN wp_postmeta m1
ON p.id = m1.post_id AND m1.meta_key = 'total_related'
LEFT JOIN wp_postmeta m2
ON p.id = m2.post_id AND m2.meta_key = 'updated'
LEFT JOIN wp_postmeta m3
ON p.id = m3.post_id AND m3.meta_key = 'cricket'
And since you aren't looking for a specific post you should be able to do this.
If you want to query specific post_types you can try something like this
SELECT p.post_title, m1.meta_value as 'total_related', m2.meta_value as 'updated', m3.meta_value as 'cricket'
FROM wp_posts p
LEFT JOIN wp_postmeta m1
ON p.id = m1.post_id AND m1.meta_key = 'total_related'
LEFT JOIN wp_postmeta m2
ON p.id = m2.post_id AND m2.meta_key = 'updated'
LEFT JOIN wp_postmeta m3
ON p.id = m3.post_id AND m3.meta_key = 'cricket'
WHERE p.post_type = 'my_custom_post_type';
Try that:
select post_title ,
MAX(CASE WHEN `meta_key`='total_related' THEN meta_value END)as 'total_related',
MAX(CASE WHEN `meta_key` = 'updated' THEN meta_value END) as 'updated' ,
MAX(CASE WHEN `meta_key` = 'cricket' THEN meta_value END) as 'cricket'
FROM wp_posts p
JOIN wp_postmeta m ON p.id = m.post_id
GROUP BY p.id
There are several approaches.
Here's an example of one way to get the specified result, using correlated subqueries in the SELECT list:
SELECT p.post_title
, ( SELECT m1.meta_value
FROM wp_post_metadata m1
WHERE m1.meta_key = 'total_related'
AND m1.post_id = p.id
ORDER BY m1.meta_key LIMIT 1
) AS `total_related`
, ( SELECT m2.meta_value
FROM wp_post_metadata m2
WHERE m2.meta_key = 'updated'
AND m2.post_id = p.id
ORDER BY m2.meta_key LIMIT 1
) AS `updated`
, ( SELECT m3.meta_value
FROM wp_post_metadata m3
WHERE m3.meta_key = 'cricket'
AND m3.post_id = p.id
ORDER BY m3.meta_key LIMIT 1
) AS `cricket`
FROM wp_posts p
WHERE p.id IN (5,8)
There are several other approaches, each with its own advantages and drawbacks.
There's a somewhat related question I referenced in a comment on the question. That question illustrates several approaches, but omits a correlated subquery approach.)
Here's how I did this dynamically - this procedure builds a SQL statement for every postmeta key for a given post type and then runs the "pivot" query for you:
This isn't the fastest query, and we use it only for migration and deep dives into data, but it does the job.
Note that this temporarily resets the max length of the concat function so you can build a large SQL statement:
CREATE PROCEDURE `wp_posts_pivot`(IN post_type_filter varchar(50))
BEGIN
/* allow longer concat */
declare max_len_original INT default 0;
set max_len_original = ##group_concat_max_len;
set ##group_concat_max_len=100000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(pm.meta_key = ''',
meta_key,
''', pm.meta_value, NULL)) AS `',
meta_key,
'`'))
INTO #sql FROM
wp_posts p
INNER JOIN
wp_postmeta AS pm ON p.id = pm.post_id
WHERE
p.post_type = post_type_filter;
SET #sql = CONCAT('SELECT p.id
, p.post_title
, ', #sql, '
FROM wp_posts p
LEFT JOIN wp_postmeta AS pm
ON p.id = pm.post_id
where p.post_type=\'',post_type_filter,'\'
GROUP BY p.id, p.post_title');
/* reset the default concat */
set ##group_concat_max_len= max_len_original;
/*
select #sql;
*/
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
You can then call this with a simple call such as this one, which will select a single row for each 'page' post type along with all meta values:
call wp_posts_pivot('page');

(mysql) Get woocommerce Order by meta_key and product_id

I have a mysql issues.
I have this select
SELECT DISTINCT t2.meta_key,t2.meta_value
FROM wp_woocommerce_order_items AS t1
JOIN wp_woocommerce_order_itemmeta AS t2 ON t1.order_item_id = t2.order_item_id
JOIN wp_posts as t3 ON t3.ID=t1.order_id
WHERE t2.order_item_id IN(SELECT distinct t1.order_item_id FROM wp_woocommerce_order_items AS t1
JOIN wp_woocommerce_order_itemmeta AS t2 ON t1.order_item_id = t2.order_item_id WHERE t2.meta_key like "_product_id" AND t2.meta_value = 99) AND t2.meta_key="member_id" AND t3.post_status like "publish"
this Select query get all "member_id"(meta_key) where the "_product_id" equals 99.
I hav3 a good result. it's maybe not "elegant" but it's works.
My problem now, I need to get all member_id where the _product_id equal 99 AND
the Order is not cancelled.
Also, I don't know which table and what is the real key that "order_status" are.
So,
Thanks For you help!
EDIT
I added the
JOIN wp_posts as t3 ON t3.ID=t1.order_id
and
WHERE t3.post_status = "publish"
The current value that I need is in the table: wp_term.
thanks
ok, I got it.
This query take all "meta_value" (here: member_id)
On all orders where
Order status is not : "failed' 'cancelled' or 'refunded'
where order have the product id is 99
Where the order is not into the trash.
so :
SELECT t2.meta_value
FROM wp_woocommerce_order_items AS t1
JOIN wp_woocommerce_order_itemmeta AS t2 ON t1.order_item_id = t2.order_item_id
WHERE t2.order_item_id IN(SELECT DISTINCT oi.order_item_id
FROM wp_posts, wp_postmeta, wp_term_relationships tr,wp_term_taxonomy tt,
wp_terms te, wp_woocommerce_order_itemmeta oi, wp_woocommerce_order_items ii
WHERE tt.taxonomy like "shop_order_status"
AND te.term_id = tt.term_id
AND te.slug NOT IN ('failed','cancelled','refunded')
AND tr.term_taxonomy_id = tt.term_taxonomy_id
AND oi.order_item_id = ii.order_item_id
AND oi.meta_key = '_product_id'
AND oi.meta_value = 99
AND ii.order_id = wp_posts.ID
AND wp_postmeta.post_id = tr.object_id
AND wp_posts.post_status = 'publish') AND t2.meta_key like "member_id"
I hope to help someOne.
If you have more elegant or more optimisation of this query.
Feel free to tell us :-)

Categories