I've spent most of my day trying to figure this out so I guess it's time I ask the experts:
I'm trying to access my WordPress DB outside of WordPress, so I'm writing queries to get output from the somewhat complicated WordPress database.
There are several tables in the DB that use meta_values and meta_keys to store data about a post or user in multiple rows.
For Example here are four tables I need to pull from:
table: wp_postmeta
post_id | meta_key | meta_value
---------+-----------------+------------
2001 | _customer_user | 3
2001 |order_description| smith
2001 | _order_total | 300
table: wp_posts
ID | post_type | post_status
----+-----------+------------
2001| shop_order| publish
table: wp_term_relationships
object_id | term_taxonomy_id
----------+-----------------
2001 | 190
table: wp_usermeta
user_id | meta_key |meta_value
---------+-----------------+----------
3 | first_name | Andy
3 | last_name | Mccormick
I've got this query to work great to display the Order Number (post_id) Customer ID, Order Description, and Order total in a single row:
SELECT wp_posts.ID, wp_posts.post_title,ot.meta_value as total,od.meta_value as order_desc, cu.meta_value as customer
FROM wp_posts
LEFT JOIN wp_postmeta AS ot ON (wp_posts.ID = ot.post_id AND ot.meta_key='_order_total')
LEFT JOIN wp_postmeta AS od ON (wp_posts.ID = od.post_id AND od.meta_key='order_description')
LEFT JOIN wp_postmeta AS cu ON (wp_posts.ID =cu.post_id AND cu.meta_key='_customer_user')
LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
WHERE wp_posts.post_type = 'shop_order'
AND wp_posts.post_status = 'publish'
AND wp_term_relationships.term_taxonomy_id = '190'
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC"
However in another area I want to list the customers by name and not just by ID so I'm trying to get their first and last name from the wp_usermeta table like this:
SELECT wp_posts.ID, cu.meta_value as customer, fn.meta_vale as fname, ln.meta_value as lname
FROM wp_posts
LEFT JOIN wp_postmeta AS cu ON (wp_posts.ID = cu.post_id AND cu.meta_key='_customer_user')
LEFT JOIN wp_usermeta AS fn ON (cu.meta_key = fn.user_id AND fn.meta_key='first_name')
LEFT JOIN wp_usermeta AS ln ON (cu.meta_key = ln.user_id AND ln.meta_key='last_name')
LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
WHERE wp_posts.post_type = 'shop_order'
AND wp_posts.post_status = 'publish'
AND wp_term_relationships.term_taxonomy_id = '190'
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC;
I've also tried:
LEFT JOIN wp_usermeta AS fn ON ((cu.meta_key='_customer_user') = fn.user_id AND fn.meta_key='first_name') along with a host of other subqueries and such.
Obviously I'm above my pay-grade in SQL queries right now so any help would be great. thanks!
I'm not sure, but you might try this:
SELECT wp_posts.ID, cu.meta_value as customer, fn.meta_vale as fname, ln.meta_value as lname
FROM wp_posts
LEFT JOIN wp_postmeta AS cu ON (wp_posts.ID = cu.post_id AND cu.meta_key='_customer_user')
LEFT JOIN wp_usermeta AS fn ON (cu.meta_value = fn.user_id AND fn.meta_key='first_name') // Note meta_value instead of meta_key
LEFT JOIN wp_usermeta AS ln ON (cu.meta_value = ln.user_id AND ln.meta_key='last_name') // Note meta_value instead of meta_key
LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
WHERE wp_posts.post_type = 'shop_order'
AND wp_posts.post_status = 'publish'
AND wp_term_relationships.term_taxonomy_id = '190'
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC;
From what I've figured out, cu.meta_value is 3 in your example as it's the user's id, while cu.meta_key (as in your query) is '_customer_id', so you rather want to match cu.meta_value than cu.meta_key. Couldn't check though, as I have no WP installation laying around.
Related
I had problem during importing products. And now some of the products are duplicated. All of the duplicated products have the same title and attribute (collection_id). Also there are a lot of duplicated media files. Is there a way to remove duplicated products? At least i want to remove products.
I had the same problem and it was I did.
1.- In my database found duplicated products (searching by sku) with the query:
SELECT meta_value, count(*) AS total FROM wp_postmeta WHERE meta_key = '_sku' GROUP BY meta_value HAVING total > 1
2.- I create a new table called wp_repeated with these skus:
CREATE TABLE wp_repeated AS SELECT meta_value, count(*) AS total FROM wp_postmeta WHERE meta_key = '_sku' GROUP BY meta_value HAVING total > 1
3.- I got the post_id from these skus:
SELECT p.ID FROM `wp_posts` as p INNER JOIN wp_postmeta as m on p.ID = m.post_id WHERE p.post_type IN ('product','product_variation') AND m.meta_key = '_sku' AND m.meta_value in (select meta_value from wp_repeated)
4.- And, finally, remove and delete from all tables where the post_id appears:
DELETE relations.*, taxes.*, terms.* FROM wp_term_relationships AS relations INNER JOIN wp_term_taxonomy AS taxes ON relations.term_taxonomy_id=taxes.term_taxonomy_id INNER JOIN wp_terms AS terms ON taxes.term_id=terms.term_id WHERE object_id IN (SELECT p.ID FROM `wp_posts` as p INNER JOIN wp_postmeta as m on p.ID = m.post_id WHERE p.post_type IN ('product','product_variation') AND m.meta_key = '_sku' AND m.meta_value in (select meta_value from wp_repeated)); DELETE FROM wp_postmeta WHERE post_id IN ( SELECT p.ID FROM `wp_posts` as p INNER JOIN wp_postmeta as m on p.ID = m.post_id WHERE p.post_type IN ('product','product_variation') AND m.meta_key = '_sku' AND m.meta_value in (select meta_value from wp_repeated)); DELETE FROM wp_posts WHERE ID IN (SELECT p.ID FROM `wp_posts` as p INNER JOIN wp_postmeta as m on p.ID = m.post_id WHERE p.post_type IN ('product','product_variation') AND m.meta_key = '_sku' AND m.meta_value in (select meta_value from wp_repeated));
I hope it can be helpful to you. Regards.
TAKE CARE: these queries remove ALL repeated products.
Okay, trying to pull off some ninja development here, but getting a little stuck. I require the help of a true expert here. Thanks in advance.
This Query works excellent to return post information and category from outside of Wordpress:
SELECT wp_posts.ID,wp_posts.post_title,wp_terms.name as category FROM wp_posts
INNER JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
INNER JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
INNER JOIN wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id
WHERE wp_term_taxonomy.taxonomy = 'category'
AND wp_posts.post_status = 'publish'
Now, this query works great for filtering by the company name, which is a meta field stored in the postmeta table. (The {$q} below is the sanitized company name)
SELECT ID,post_title,post_date,post_name,post_author FROM wp_posts,wp_postmeta
WHERE ID = wp_postmeta.post_id AND meta_key = 'company'
AND meta_value = \"{$q}\" AND wp_posts.post_status = 'publish'
ORDER BY post_date DESC
Anyway, both queries work great on their own. However, I want to combine them into one query so that I can select the category but still filter by company.
Any thoughts? I would love to hear your ideas on how to solve this problem. I'd give you 3x points for this answer if I could.
One way to accomplish this:
SELECT wp_posts.ID,wp_posts.post_title,wp_terms.name as vert FROM wp_posts
INNER JOIN wp_term_relationships on wp_posts.ID = wp_term_relationships.object_id
INNER JOIN wp_term_taxonomy on wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
INNER JOIN wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id
WHERE wp_term_taxonomy.taxonomy = 'category'
AND wp_posts.post_status = 'publish'
AND wp_posts.ID IN (SELECT post_id FROM wp_postmeta WHERE meta_key = 'company' AND meta_value = \"{$q}\" ) LIMIT 0,99999
MySQL is driving me nuts. I've been requested for a csv file of Wordpress data. The posts have a bunch of meta entries and for the most part, I have things coming out ok. But I'm trying to connect user id's in the Other Authors to their display names (See below). The difficulty I'm having is trying to output each display name in that column.
Tracking Number | Post Title | Post Date | Primary Author | Other Authors
1153 | Title of Post | 2013/03/06 | Tom Smith | 213, 100, 600
And here's my query:
SELECT results.ID as ID, results.post_title as post_title, results.post_date
as post_date, results.post_content as post_content, u.display_name as
primary_author, results.other_authors as other_authors
FROM (SELECT m.meta_value as ID,p.post_title as post_title, p.post_date as
post_date,p.post_content as post_content,m2.meta_value as primary_author,
m3.meta_value as other_authors
FROM wp_posts p
INNER JOIN wp_postmeta m ON (p.ID = m.post_id)
INNER JOIN wp_postmeta m2 ON (p.ID = m2.post_id)
INNER JOIN wp_postmeta m3 ON (p.ID = m3.post_id)
WHERE p.post_type='post' AND p.post_status NOT IN ('trash') AND
(m.meta_key='idea_tracking_num' AND m.meta_value != '')
AND m2.meta_key='primary_author' AND m3.meta_key='other_authors'
ORDER BY p.post_date
DESC) as results
INNER JOIN wp_users u on (u.ID = results.primary_author)
INNER JOIN wp_users u2 on (u2.ID = results.other_authors)
I've also tried this, but it just outputs the first one:
SELECT results.ID as ID, results.post_title as post_title, results.post_date
as post_date, results.post_content as post_content, u.display_name as
primary_author, u2.display_name as other_authors
FROM (SELECT m.meta_value as ID,p.post_title as post_title, p.post_date as
post_date,p.post_content as post_content,m2.meta_value as primary_author,
m3.meta_value as other_authors
FROM wp_posts p
INNER JOIN wp_postmeta m ON (p.ID = m.post_id)
INNER JOIN wp_postmeta m2 ON (p.ID = m2.post_id)
INNER JOIN wp_postmeta m3 ON (p.ID = m3.post_id)
WHERE p.post_type='post' AND p.post_status NOT IN ('trash') AND
(m.meta_key='idea_tracking_num' AND m.meta_value != '')
AND m2.meta_key='primary_author' AND m3.meta_key='other_authors'
ORDER BY p.post_date
DESC) as results
INNER JOIN wp_users u on (u.ID = results.primary_author)
INNER JOIN wp_users u2 on (u2.ID = results.other_authors)
I have some regular WordPress posts that I need to get from the database by parent category, and order by the results of a custom table in the database that I have made.
The parent category that I want to retrieve posts for (including children) is called explorer with the id of 29.
The custom table is called wp_upvotes. in this table there are a few columns, but the only columns that we care about would probably be id and postID. I want to order the wp_posts by the number of rows that has the postID equal to the wp_post.ID, and if there are no rows in that table for the other posts, then they should be ordered by date at the end. I want the most number of upvotes to the least number of upvotes by date.
The query I have tried is this (it returns only the first post, not all of them):
$catIDs = array(29,30,31,32);
SELECT wp_posts.*, COUNT(wp_upvotes.id) AS upvotes FROM wp_posts
LEFT JOIN wp_upvotes ON (wp_posts.ID = wp_upvotes.postID)
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy
ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
AND wp_term_taxonomy.taxonomy = 'category'
AND wp_term_taxonomy.term_id IN (" . implode(',', $catIDs) . "))
AND wp_posts.post_status = 'publish'
ORDER BY upvotes DESC, wp_posts.post_date DESC
When I remove the LEFT JOIN for the wp_upvotes table it returns all of the correct posts.. Why is it only returning one row when I am using a LEFT JOIN?
SELECT wp_posts.* FROM wp_posts
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy
ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
AND wp_term_taxonomy.taxonomy = 'category'
AND wp_term_taxonomy.term_id IN (" . implode(',', $catIDs) . "))
AND wp_posts.post_status = 'publish'
ORDER BY wp_posts.post_date DESC
Looks like the main factor was to use ORDER BY wp_posts.ID for whatever reason to make it show all of the rows instead of just one.. Odd but here's my final code to do what I wanted to do above:
SELECT wp_posts.*, COUNT(wp_upvotes.id) AS upvotes FROM wp_posts
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy
ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
AND wp_term_taxonomy.taxonomy = 'category'
AND wp_term_taxonomy.parent = 29)
LEFT JOIN wp_upvotes ON (wp_posts.ID = wp_upvotes.postID)
WHERE wp_posts.post_status = 'publish'
GROUP BY wp_posts.ID
ORDER BY upvotes DESC, wp_posts.post_date DESC
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');