wordpress phpadmin SQL database query to get results in columns - mysql

In my wordpress website I have multiple custom fields under post type 'home_decor', using the below query returns two field 'post id' and 'hd_product_description'. Currently, I am using this query to export fields one by one and then vlookup by post id. I have 7 fields in total, can someone help me with the SQL query that will return all seven columns from wp_postmeta. I have to export data from time to time and its become a long process.
SELECT * FROM `wp_postmeta` WHERE `meta_key` = 'product_description'
post id product_description retail_price sale_price product_sku product_name
------- ------------------- ------------ ---------- ----------- ------------
1245 about the product $125 $115 1245alt furniture

Your problem is to retrieve multiple attributes for your posts from your wp_postmeta table. It's known as an entity - attribute - value table in the language of database design. It's a notorious pain in the xxx neck to use, but it is extensible.
You need to join the postmeta table multiple times for this, one time for each named attribute you want. Here is the pattern.
SELECT wp_posts.ID post_id,
product_description.meta_value product_description,
retail_price.meta_value retail_price
sale_price.meta_value sale_price
/* always start with wp_posts, because some attibutes might be missing */
FROM wp_posts
/* left join wp_postmeta giving it an alias. put meta_key into ON clause */
LEFT JOIN wp_postmeta product_description
ON product_description.post_id = wp_posts.ID
AND product_description.meta_key = 'product_description'
/* and again for the next attribute */
LEFT JOIN wp_postmeta retail_price
ON retail_price.post_id = wp_posts.ID
AND retail_price.meta_key = 'retail_price'
/* and again */
LEFT JOIN wp_postmeta sale_price
ON sale_price.post_id = wp_posts.ID
AND sale_price.meta_key = 'sale_price'
The trick is to use a separate LEFT JOIN to the wp_postmeta table for every attribute. For each of those LEFT JOIN operations, give the table an alias that's unique. For example LEFT JOIN wp_postmeta sale_price assigns the alias sale_price to this particular use of wp_postmeta.
Then, for each column in your SELECT clause, mention the alias and meta_value, then assign an alias to the column. For example, sale_price.meta_value sale_price.
Why LEFT JOIN instead of ordinary inner JOIN? If you used inner JOIN, your result set would only contain rows for posts that have every attribute you want. With LEFT JOIN you'll get NULL values for missing attributes. That is much more useful unless your data is absolutely perfect. (Umm, not much real world data is so perfect.)

Related

Update MySQL column in one table based on the number of rows in another table

I have MySQL table labeled wp_posts that contains a comment_count column. It also contains an ID column.
I have another table called wp_comments with a column labeled comment_post_ID. The comment_post_ID column contains the ID associated with the post that the comment is located on. For example, if the post's ID is 10 and there is a comment located on that post, the comment_post_ID value for that comment will be 10. Multiple comments (wp_comments) will have the same comment_post_ID value.
In other words, if there are 10 wp_comments entries that all have the comment_post_ID value of 7, the value of the comment_count column will be 10 on the wp_posts entry that has the ID value of 7.
I need to up the comment_count column for each wp_posts entry based on how many entries in the wp_comments table share the same ID. The below code obviously won't work but maybe it will give a better picture of what I am needing:
UPDATE wp_posts
INNER JOIN wp_posts ON wp_comments.comment_post_ID(count) = wp_posts.comment_count
The update syntaxis is like this
UPDATE wp_posts P
JOIN wp_comments C
ON P.id = C.post_id
SET P.count = C.something
But to calculate the count you need use an aggregated query first
UPDATE wp_posts P
JOIN (SELECT post_id, COUNT(*) as total_comments
FROM wp_comments
GROUP BY post_id ) as C
ON P.id = C.post_id
SET P.count = C.total_comments
Additional Note: You probably don't want add this count column anyway, because you will have to update the field every time someone makes a comment. Maybe better create a view with the above query so you can get the count when need it.

Using AND between CASE statements in the WHERE clause SQL query

I have written a query which is as follows -
SELECT user_id, display_name, user_email, meta_key, meta_value
FROM wp_usermeta um INNER JOIN wp_users u ON um.user_id = u.id
WHERE
CASE
WHEN meta_key = "renewal_date" THEN meta_value = "a"
WHEN meta_key = "wp_user_level" THEN meta_value <> "10"
END
I need the user_id of the two 'when' statements to be equal. By that I mean, if the same user(having the same user_id) has meta_key as renewal_date and corresponding meta_value as a, and the same user has meta_key as wp_user _level and has the corresponding meta_value as 10 then he should not show in the result list. With my limited knowledge of SQL I was considering using AND between the WHEN statements but it gives me a syntactic error.
From your description I think I see what you are trying to do, but your query won't work like that. It looks like you have several rows per user id in the wp_usermeta table. This is known as an EAV model (entity-attribute-value) and that model makes reporting quite difficult, because you have rows that should be columns.
One way of getting it working is to join the wp_usermeta table multiple times (so rows become columns essentially), like this:
SELECT u.id, u.display_name, u.user_email,
rd.meta_value AS renewal_date, ul.meta_value AS wp_user_level
FROM wp_users u
LEFT JOIN wp_usermeta rd ON rd.user_id=u.id AND rd.meta_key='renewal_date'
LEFT JOIN wp_usermeta ul ON ul.user_id=u.id AND ul.meta_key='wp_user_level'
WHERE rd.meta_value = 'a'
AND ul.meta_value <> '10'
Please note that users who have no 'wp_user_level' data will be included in this report. If you need to filter those ones out you can replace LEFT JOIN with INNER JOIN.

Woocommerce SQL query to show products sold this week?

Woocommerce has a reporting tool that will show me the top products sold for the last 7 days. But it only shows the top 12 products.
I am wanting to create a SQL query that will show me all products with their total count sold for the last 7 days instead of just the top 12.
Has anyone done this before?
WooCommerce borrows heavily from the way WordPress itself stores data: a Post serves as the basic data object with a handful of columns common to all custom posts. Any unique data specific to a custom type is stored as key value pairs in post_meta. This means there aren't clean columns or tables to query for things like order line items, sku, line item price, etc.
It's worth mentioning that for orders, WC does not store products it stores line items. This is because you can add fees, generic line items and possibly other things to an order that are not products. Also, WC needs to store the price at the time of the order as the customer may have had a discount or the product price may have changed.
WooCommerce uses both the WordPress postmeta table AND its own order_itemmeta table. Here's how that breaks down:
The order itself is stored as a custom post type of "shop_order" in the wp_posts table
Order line items are stored in a relationship table called wp_woocommerce_order_items
Order item details are stored as key value pairs in wp_woocommerce_order_itemmeta
Finaly order details are stored in the wp_postmeta table
So, let's say you want to see all line items for a period of time and you want to know things like the item title, price and what order it belonged to. To do this you must JOIN multiple tables and either JOIN or subquery the meta tables for the specific fields you want. In the example below I used subqueries because I believe they are more readable, please note that JOINs are very likely faster.
SELECT
-- Choose a few specific columns related to the order
o.ID as order_id,
o.post_date as order_created,
-- These come from table that relates line items to orders
oi.order_item_name as product_name,
oi.order_item_type as item_type,
-- We have to subquery for specific values and alias them. This could also be done as a join
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_product_id") as product_id,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_product_variation_id") as variant_id,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_qty") as qty,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_fee_amount") as fee,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_line_subtotal") as subtotal,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_line_subtotal_tax") as tax,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_line_total") as total,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_tax_class") as tax_class,
(SELECT meta_value FROM wp_woocommerce_order_itemmeta WHERE order_item_id = oi.order_item_id AND meta_key = "_tax_status") as tax_status,
-- This wasn't specifically mentioned in the question but it might be nice to have some order meta data too
(SELECT meta_value FROM wp_postmeta WHERE post_id = o.ID AND meta_key = "_order_total") as order_total,
(SELECT meta_value FROM wp_postmeta WHERE post_id = o.ID AND meta_key = "_customer_user") as user_id
FROM wp_posts o
LEFT JOIN wp_woocommerce_order_items oi ON oi.order_id = o.id
LEFT JOIN wp_posts p ON p.ID = oi.order_item_id
WHERE o.post_type = "shop_order"
As you can see it takes a subquery/join for every line item field you want making these queries pretty expensive. I suspect that WC limits how much is queried for reports for this reason.
This answer was tested against WC version 3.3.4.
Instead of writin a new query just modify the existing one with filter:
woocommerce_reports_get_order_report_query
Is seems that the limit is the same for all parts of the reports page, so changing this will affect all queries with limit clause. I would not go too far with the number of products because a new sql query is executed for each product listed.
add_filter( 'woocommerce_reports_get_order_report_query', function( $query )
{
if ( isset( $query['limit'] ) ) $query['limit'] = 'LIMIT 20'; <-- set limit to 20 products
return $query;
});
Just a guess
....WHERE dateColumn BETWEEN DATE_SUB(NOW(),INTERVAL 1 WEEK) AND NOW()
Add more info,for a more precise answer.

MySQL | LEFT JOIN wp_posts and wp_postmeta

I like to LEFT JOIN both tables, wp_posts and wp_postmeta. In my posts i have create several meta box options.
Lets say I have create a custom post type called "ads" and for each ad, i have the publication date and the expiration date as meta options.
the question is, how can I join the two tables, in order to get the ID of the post, from the wp_posts table where the current date is higher than the start date in the post meta table and lower than the expiration date in the post meta table.
for non WP users the wp_posts table is a traditional table, where each row represents a post and the wp_postmeta is a key value pare table where based on the post id, contains more than one row to describe the meta options of the post.
Is there a way to make that query in a single MySQL Query ?
kind regards.
I take you to mean that "start date" is the "publication_date".
Absent a schema definition, I will guess at the column names and datatypes
One way to get this would be to use correlated subqueries in EXISTS predicates, though this may not be the most efficient approach:
SELECT p.id
FROM wp_posts p
WHERE EXISTS
( SELECT 1
FROM wp_postmeta m1
WHERE m1.wp_posts_id = p.id
AND m1.meta_option_name = 'publication date'
AND m1.meta_option_date_value <= NOW()
)
AND EXISTS
( SELECT 1
FROM wp_postmeta m2
WHERE m2.wp_posts_id = p.id
AND m2.meta_option_name = 'expiration date'
AND m2.meta_option_date_value > NOW()
)
You specifically asked about using a LEFT JOIN
An equivalent result can be obtained using LEFT JOIN operations (although this query is really equivalent to doing INNER JOIN operations):
SELECT p.id
FROM wp_posts p
LEFT
JOIN wp_postmeta m1
ON m1.wp_posts_id = p.id
AND m1.meta_option_name = 'publication date'
AND m1.meta_option_date_value <= NOW()
LEFT
JOIN wp_postmeta m2
ON m2.wp_posts_id = p.id
AND m2.meta_option_name = 'expiration date'
AND m2.meta_option_date_value > NOW()
WHERE m1.id IS NOT NULL
AND m2.id IS NOT NULL
GROUP
BY p.id

MySQL - How to JOIN with an unexisting index?

I have a table in my DB called ORDERS and it looks like this:
ID_section (int), ID_price (int), ID_city (int), ID_company (int)
And I want to use the JOIN method to set names to the ID's.
What I would do is:
SELECT * FROM ORDERS
JOIN sections ON sections.id=orders.ID_section
JOIN prices ON prices.id=orders.ID_price
JOIN cities on cities.id=orders.ID_cities
JOIN companies ON companies.id=orders.ID_company
But the point is, that in ORDERS table can be inserted value of 0 and it means - all the sections/prices/cities/companies, but when I run my query, only the values, that their ID exist in the other table show up.
Any ideas? Thanks.
If I understand you question correctly and having, for example, ID_section = 0 means that the order belongs to all the section then the following query should do the trick.
SELECT * FROM ORDERS
JOIN sections ON sections.id=orders.ID_section OR orders.ID_section = 0
JOIN prices ON prices.id=orders.ID_price OR orders.ID_price = 0
JOIN cities on cities.id=orders.ID_cities OR orders.ID_cities = 0
JOIN companies ON companies.id=orders.ID_company OR orders.ID_company = 0
If, on the other hand, you want to retrieve all orders regardless if they have sections, prices, etc. associated, then it is sufficient to put LEFT JOIN where you have JOIN. (But this situation does not result from your question! I only added it because people seem to understand that.)
Use LEFT JOIN instead of JOIN (which is a shorthand for INNER JOIN)
Experiment with LEFT and RIGHT OUTER JOIN s and you'll be able to figure out what you need to do. Basically a LEFT or RIGHT OUTER JOIN will insert NULLS into columns where no data exists but still do the joins.
There are various resources on the web that explain this.