Why I keep getting posts.ID unknown column while the column exists? - mysql

This is my WooCommerce SQL query below. I keep getting the error,
Unknown column 'posts.ID' is 'on clause'
but my posts.ID column does exist.
SELECT DISTINCT posts.ID as product_id, posts.post_parent as parent_id FROM wp_posts posts,
wp_terms terms, wp_term_relationships term_relationships LEFT JOIN wp_wc_product_meta_lookup
wc_product_meta_lookup ON posts.ID=wc_product_meta_lookup.product_id WHERE
posts.ID=term_relationships.object_id AND term_relationships.term_taxonomy_id=terms.term_id
AND terms.name!='exclude-from-catalog' AND posts.post_type IN ('product')
AND ( ( ( posts.post_title LIKE '%bruno%') OR ( posts.post_excerpt LIKE '%bruno%')
OR ( posts.post_content LIKE '%bruno%' ) OR ( wc_product_meta_lookup.sku LIKE '%bruno%' ) ))
AND posts.post_status IN ('publish') ORDER BY posts.post_parent ASC, posts.post_title ASC;

Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
So, write the query correctly as:
SELECT DISTINCT p.ID as product_id, p.post_parent as parent_id
FROM wp_posts p JOIN
wp_term_relationships
ON p.id = tr.object_id JOIN
wp_terms t
ON tr.term_taxonomy_id = t.term_id LEFT JOIN
wp_wc_product_meta_lookup pml
ON p.ID = pml.product_id
WHERE t.name <> 'exclude-from-catalog' AND
p.post_type IN ('product') AND
(p.post_title LIKE '%bruno%' OR
p.post_excerpt LIKE '%bruno%' OR
p.post_content LIKE '%bruno%' OR
pml.sku LIKE '%bruno%'
) AND
p.post_status IN ('publish')
ORDER BY p.post_parent ASC, p.post_title ASC;
Notes:
The specific problem is that , affects the scoping of identifiers. You cannot reference a table alias from before the comma in an ON clause after the comma.
I see no reason to duplicate table names.
Using table aliases is good, but the query is simpler if the aliases are shorter.

Related

SQL - Slow SQL Query

I have a sql query (see below) for wordpress which is taking around 4-5secs to get results. It gives all order ids which have a product/variation id in it.
I want to make it more fast, any help?
SELECT p.ID order_id
FROM wp_posts p
INNER JOIN wp_woocommerce_order_items i ON p.ID=i.order_id
INNER JOIN wp_woocommerce_order_itemmeta im ON i.order_item_id=im.order_item_id
WHERE im.meta_key IN ('_product_id','_variation_id')
AND im.meta_value IN ('703899','981273','981274','981275')
AND p.post_status IN ('wc-completed')
GROUP BY p.ID HAVING COUNT(p.ID)>1
ORDER BY p.post_date desc
LIMIT 0, 20
Above query EXPLAIN:
Why do you join when you only want to select IDs from wp_posts anyway?
SELECT p.ID order_id
FROM wp_posts p
WHERE p.post_status = 'wc-completed'
AND p.ID IN
(
SELECT i.order_id
FROM wp_woocommerce_order_items i
JOIN wp_woocommerce_order_itemmeta im ON im.order_item_id = i.order_item_id
WHERE im.meta_key IN ('_product_id','_variation_id')
AND im.meta_value IN ('703899','981273','981274','981275')
GROUP BY i.order_id
HAVING COUNT(*) > 1
)
ORDER BY p.post_date DESC
LIMIT 0, 20;
Now let's think about how the DBMS can address this. It can look for posts with status 'wc-completed', if there are only few such rows and then check whether they represent an order with more than one of the desired items. This would ask for these indexes:
create index idx1 on wp_posts(post_status, id, post_date);
create index idx2 on wp_woocommerce_order_items(order_id, order_item_id);
create index idx3 on wp_woocommerce_order_itemmeta(order_item_id, meta_key, meta_value);
Or it could look for the desired products, see whether an order contains more than one of them and then check whther this relates to a post with status = 'wc-completed'. That would ask for these indexes:
create index idx4 on wp_woocommerce_order_itemmeta(meta_key, meta_value, order_item_id);
create index idx5 on wp_woocommerce_order_items(order_item_id, order_id);
create index idx6 on wp_posts(id, post_status, post_date);
We don't know which way the DBMS will prefer, so we create all six indexes. Then we look at the explain plan to see which are being used and remove the others. Maybe the DBMS even sees no advantage in using indexes here at all, but I find this unlikely.
The first thing you can try doing is trimming what data you fetch.
That means:
Not fetching fields that you don't need/check
Implementing our constrains before joining
SELECT
p.ID order_id
FROM
(SELECT id, post_status, post_date FROM wp_posts WHERE post_status = 'wc-completed') p,
(SELECT order_id, order_item_id FROM wp_woocommerce_order_items) i,
(
SELECT
order_item_id,
meta_key,
meta_value
FROM
wp_woocommerce_order_itemmeta
WHERE
meta_key IN ('_product_id','_variation_id')
AND meta_value IN ('703899','981273','981274','981275')
) im
WHERE
p.ID = i.order_id
AND i.order_item_id = im.order_item_id
GROUP BY
p.ID
HAVING
COUNT(p.ID)>1
ORDER BY
p.post_date desc
LIMIT
0, 20
Edit:
If Inner joins are necessary, you can try:
SELECT
p.ID order_id
FROM
(SELECT id, post_status, post_date FROM wp_posts WHERE post_status = 'wc-completed') p
INNER JOIN
(SELECT order_id, order_item_id FROM wp_woocommerce_order_items) i
ON
p.ID = i.order_id
INNER JOIN
(
SELECT
order_item_id,
meta_key,
meta_value
FROM
wp_woocommerce_order_itemmeta
WHERE
meta_key IN ('_product_id','_variation_id')
AND meta_value IN ('703899','981273','981274','981275')
) im
ON
i.order_item_id = im.order_item_id
GROUP BY
p.ID
HAVING
COUNT(p.ID)>1
ORDER BY
p.post_date desc
LIMIT
0, 20
ps* I hope my syntax is correct ˙ my SQL is quite rusty

How to delete entries from a SELECT query result in mysql?

I have the following SQL query :
SELECT wp_posts.* , wicl_translations.*
FROM wp_posts wp_posts join wp_icl_translations wicl_translations
ON (wicl_translations.element_id = wp_posts.ID)
WHERE (wicl_translations.language_code = 'es-es'
AND wicl_translations.element_type ='post_product'
AND wp_posts.post_type = 'product' ) GROUP BY wp_posts.ID
This returns all the results I need to delete from my database so I have tried several DELETE queries but getting syntax errors in all of them .
Example :
DELETE FROM wp_posts
WHERE (
SELECT wp_posts.* , wicl_translations.*
FROM wp_posts wp_posts join wp_icl_translations wicl_translations
ON (wicl_translations.element_id = wp_posts.ID)
WHERE (wicl_translations.language_code = 'pt-pt'
AND wicl_translations.element_type ='post_product'
AND wp_posts.post_type = 'product' ) GROUP BY wp_posts.ID
)
);
Also tried this :
DELETE FROM wp_posts WHERE wp_posts.ID = ANY IN (
SELECT wp_posts.ID, wicl_translations.*
FROM wp_posts wp_posts join wp_icl_translations wicl_translations
ON (wicl_translations.element_id = wp_posts.ID)
WHERE (wicl_translations.language_code = 'es-es'
AND wicl_translations.element_type ='post_product'
AND wp_posts.post_type = 'product' ) GROUP BY wp_posts.ID
)
It`s a complex aggregated query and I lack the mysql knowledge to properly write a rule for deleting these results .
How could I approach this ?
Thanks
If we have a complex query that returns the id value of rows in wp_posts that we want to delete (assuming that id is the primary key or a unique key of a row in the table)... as an example
SELECT p.id
FROM wp_posts p
JOIN wp_icl_translations t
ON t.element_id = p.id
WHERE t.language_code = 'es-es'
AND t.element_type = 'post_product'
AND p.post_type = 'product'
GROUP
BY p.id
We can then use that query as an inline view. We wrap the query in parens and reference it in the FROM clause of another query. MySQL requires that we assign an alias to thhe inline view (or derived table in the MySQL vernacular).
We can join the result from the inline view that back to the table we want to remove rows from. We write this a SELECT statement first
SELECT r.*
FROM ( -- inline view
SELECT p.id
FROM wp_posts p
JOIN wp_icl_translations t
ON t.element_id = p.id
WHERE t.language_code = 'es-es'
AND t.element_type = 'post_product'
AND p.post_type = 'product'
GROUP
BY p.id
) q
JOIN wp_posts r
ON r.id = q.id
to return the set of rows to be removed. We can verify that this is the intended set, or insert (create table as) the set of rows into backup...
Once we are confident that the SELECT is returning the rows we want to remove, we can convert it into a DELETE statement by replacing the SELECT keyword with DELETE.
DELETE r.*
FROM ( -- inline view
SELECT p.id
FROM wp_posts p
JOIN wp_icl_translations t
ON t.element_id = p.id
WHERE t.language_code = 'es-es'
AND t.element_type = 'post_product'
AND p.post_type = 'product'
GROUP
BY p.id
) q
JOIN wp_posts r
ON r.id = q.id
You'r on the right track !
You just miss the correct WHERE condition :
DELETE FROM wp_posts WHERE wp_posts.ids IN (...)
Make sure the result has only one column wich you shall refer to when deleting data from the targetted tables. The delete queries will be equal to the number of tables you will require to delete from ie.
DELETE FROM table_1 where common_column in (YOUR_SELECT_QUERY);
DELETE FROM table_2 where common_column in (YOUR_SELECT_QUERY);
DELETE FROM table_3 where common_column in (YOUR_SELECT_QUERY);
DELETE FROM table_nth where common_column in (YOUR_SELECT_QUERY);
Your select query be like,
SELECT GROUP_CONCAT(temp_tbl.ID) FROM (SELECT wp_posts.* , wicl_translations.*
FROM wp_posts wp_posts join wp_icl_translations wicl_translations
ON (wicl_translations.element_id = wp_posts.ID)
WHERE (wicl_translations.language_code = 'es-es'
AND wicl_translations.element_type ='post_product'
AND wp_posts.post_type = 'product' ) GROUP BY wp_posts.ID) AS temp_tbl

mysql sum returning wrong value

Hi there so i have this problem in the following query, inside wp_wti_like_post i have number of rows with similar post_id and with value column as 1 or -1.
So let's say for post with id 727 i have only one row , so the sum should be 1, but don't know why it does return 4 and when there are two rows with 727 it does return 8 query is below:
SELECT wp_posts. * ,
SUM( wp_wti_like_post.value ) -4 AS total_sum,
wp_wti_like_post.post_id
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 )
JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
LEFT JOIN wp_wti_like_post ON ( wp_posts.ID = wp_wti_like_post.post_id )
WHERE wp_term_taxonomy.taxonomy = 'category'
AND wp_term_taxonomy.term_id IN ('$c_cid')
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish')
GROUP BY wp_posts.ID
HAVING SUM( wp_wti_like_post.value ) > $min_like
ORDER BY wp_posts.post_date DESC
You are using joins among many tables and there may b a chance that any of them has many associations for a post_id therefore your sum is incorrect i suggest you to use a sub select for your like table and calculate sum in sub select and then join with your main query
SELECT
p.*, COALESCE(l.sum_like,0) AS total_sum,
l.post_id
FROM
wp_posts p
INNER JOIN wp_term_relationships ttr
ON (p.ID = ttr.object_id)
INNER JOIN wp_term_taxonomy tt
ON (ttr.term_taxonomy_id = tt.term_taxonomy_id)
LEFT JOIN (
SELECT post_id ,SUM(`value`) sum_like
FROM wp_wti_like_post
GROUP BY post_id
) l ON (p.ID = l.post_id)
WHERE tt.taxonomy = 'category'
AND tt.term_id IN ('21')
AND p.post_type = 'post'
AND (p.post_status = 'publish')
HAVING total_sum > 2
ORDER BY p.post_date DESC
Also note i have removed wp_postmeta join because its not used in your selection criteria and neither in your filter criteria also wp_postmeta stores different attributes for each post so i guess this table is producing more rows thats why wrong sum is calculated.
Removed -4 from query

MySQL query with SUM and order

What is wrong with my query? Can somebody help me please?
I get this errormessage
"Unknown column 'wp_gdsr_data_article.
(SUM(user_voters)+SUM(visitor_voters))' in 'order clause'"
but the 'wp_gdsr_data_article' colum exist
SELECT *
FROM `wp_posts`
INNER JOIN wp_term_relationships ON wp_term_relationships.object_id = ID AND wp_term_relationships.term_taxonomy_id = 1
INNER JOIN wp_gdsr_data_article ON post_id = ID
WHERE `post_status` = 'publish'
AND `post_type` = 'post'
ORDER BY `wp_gdsr_data_article`.`(SUM(user_voters)+SUM(visitor_voters))` DESC
LIMIT 1 , 30
You are using an expression in the ORDER clause which not a table's column.
Hence you can't use a table identifier on the outcome of an expression.
This is wrong.
ORDER BY `wp_gdsr_data_article`.`(SUM(user_voters)+SUM(visitor_voters))` DESC
Change it to:
ORDER BY (SUM(user_voters)+SUM(visitor_voters)) DESC
And you can't directly use any aggregate function in ORDER BY clause like that.
Calculate SUM... parts separately and then use in ORDER BY.
SELECT * from (
SELECT *, (SUM(user_voters)+SUM(visitor_voters)) total
FROM `wp_posts`
INNER JOIN wp_term_relationships
ON wp_term_relationships.object_id = ID
AND wp_term_relationships.term_taxonomy_id = 1
INNER JOIN wp_gdsr_data_article
ON post_id = ID
WHERE `post_status` = 'publish'
AND `post_type` = 'post'
LIMIT 1 , 30
) results
ORDER BY total
Refer to: How to ORDER BY a SUM() in MySQL?
Remove quotes from all columns and tablenames in your statement. Besides the Order by part should base on a column or an evaluated value in our statement, the way you use it is wrong. you will need to evaluate the part which you use in the order by section before using it for the order by, something like this (untested):
SELECT (SUM(wp_gdsr_data_article.user_voters)+SUM(wp_gdsr_data_article.visitor_voters) as total_voters), *
FROM wp_posts
INNER JOIN wp_term_relationships
ON wp_term_relationships.object_id = ID
AND wp_term_relationships.term_taxonomy_id = 1
INNER JOIN wp_gdsr_data_article
ON post_id = ID
WHERE post_status = 'publish' AND post_type = 'post'
ORDER BY total_voters DESC
LIMIT 1 , 30
Try this
SELECT *, (SUM(wp_gdsr_data_article.user_voters)+SUM(wp_gdsr_data_article.visitor_voters)) AS someSum
FROM `wp_posts`
INNER JOIN wp_term_relationships ON wp_term_relationships.object_id = ID AND wp_term_relationships.term_taxonomy_id = 1
INNER JOIN wp_gdsr_data_article ON post_id = ID
WHERE `post_status` = 'publish'
AND `post_type` = 'post'
ORDER BY someSum DESC
LIMIT 1 , 30

Filter posts in a query if they have only one certain tag

Querying wordpress posts according to their tags can look like this (if I pieced it together correctly - I removed irrelevant parts from the query):
SELECT wposts.ID AS ID,
wposts.post_title, wposts.post_status, wposts.post_name,
tag_terms.term_id AS tag_id
FROM `wp_posts` AS wposts
INNER JOIN wp_term_relationships AS tag_term_relationships ON (wposts.ID = tag_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tag_term_taxonomy ON (tag_term_relationships.term_taxonomy_id = tag_term_taxonomy.term_taxonomy_id AND tag_term_taxonomy.taxonomy = 'post_tag')
INNER JOIN wp_terms AS tag_terms ON (tag_term_taxonomy.term_id = tag_terms.term_id)
WHERE wposts.ID = '12345'
AND wposts.post_type = 'post'
AND wposts.post_status NOT LIKE 'private'
AND tag_terms.term_id = '55'
GROUP BY wposts.ID
ORDER BY wposts.post_date ASC
This should query all posts with tag id 55.
What I need to do is to filter out all posts that only contain this single tag, but no other tags.
So I want to show a post if it has the tags 23,34,55,67
But I don't want to show the post if it has the tag 55 (and no other tags).
Posts that do not contain this certain tag should be included in the query as well.
How do I do this?
Try adding HAVING condition between GROUP BY and ORDER BY:
...
GROUP BY wposts.ID
HAVING COUNT( tag_terms.term_id ) <> 1
OR MAX( tag_terms.term_id ) <> 55
ORDER BY wposts.post_date ASC
and change your WHERE condition to check only for post type and status.
Also if you don't select anything other than tag_id from wp_terms joining it is not necessary as you can just use term_id from wp_term_taxonomy.
If you want all the posts with a certain tag, then why have you specified the post ID in the query ?
This following query will show all posts with the given tag id
SELECT wposts.ID AS ID,
wposts.post_title, wposts.post_status, wposts.post_name,
tag_terms.term_id AS tag_id
FROM `wp_posts` AS wposts
INNER JOIN wp_term_relationships AS tag_term_relationships ON (wposts.ID = tag_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tag_term_taxonomy ON (tag_term_relationships.term_taxonomy_id = tag_term_taxonomy.term_taxonomy_id AND tag_term_taxonomy.taxonomy = 'post_tag')
INNER JOIN wp_terms AS tag_terms ON (tag_term_taxonomy.term_id = tag_terms.term_id)
WHERE wposts.post_type = 'post'
AND wposts.post_status NOT LIKE 'private'
AND tag_terms.term_id = '55'
GROUP BY wposts.ID
ORDER BY wposts.post_date ASC
Now, if you want to make sure that these posts have only the given tag id, nest the query as follows :
SELECT wposts.ID AS ID,
wposts.post_title, wposts.post_status, wposts.post_name,
tag_terms.term_id AS tag_id
FROM `wp_posts` AS wposts
INNER JOIN wp_term_relationships AS tag_term_relationships ON (wposts.ID = tag_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tag_term_taxonomy ON (tag_term_relationships.term_taxonomy_id = tag_term_taxonomy.term_taxonomy_id AND tag_term_taxonomy.taxonomy = 'post_tag')
INNER JOIN wp_terms AS tag_terms ON (tag_term_taxonomy.term_id = tag_terms.term_id)
WHERE wposts.post_type = 'post'
AND wposts.post_status NOT LIKE 'private'
AND tag_terms.term_id = '55'
GROUP BY wposts.ID
HAVING COUNT( tag_terms.term_id ) <> 1
OR MAX( tag_terms.term_id ) <> 55
ORDER BY wposts.post_date ASC