SQL condition if doesn't exist - mysql

so I have this SQL query:
SELECT
p.ID
FROM
`cdlr_posts` p,
cdlr_postmeta pm
WHERE
pm.post_id=p.ID AND
`post_type` = 'shop_order' AND
pm.meta_key = '_statusCDLR' AND
pm.meta_value <> 1
group by
p.ID
What I need is to show all the IDS if they match with those conditions, but I will also like to show the ones that do not contain the "_statusCDLR" meta_key I tried something like this with no luck:
WHERE
pm.post_id=p.ID AND
`post_type` = 'shop_order' AND
(pm.meta_key = '_statusCDLR' AND pm.meta_value <> 1 OR pm.meta_key <> '_statusCDLR')
group by
Any help will be appreciated to achieve what I need.

I understand that your requirement is to select the id of posts that :
either have a corresponding record in cdlr_post_meta with meta_key = 'statusCDLR' and meta_value <> 1
or do not have a record cdlr_post_meta with meta_key = 'statusCDLR'
A strategy to achieve this is to use a LEFT JOIN to search for a record in cdlr_post_meta with meta_key = 'statusCDLR', and then implement the rest of the logic in the WHERE clause (if there is no corresponding record, the columns of pm are all NULL).
SELECT p.ID
FROM cdlr_posts p
LEFT JOIN cdlr_postmeta pm
ON pm.post_id = p.ID AND pm.meta_key = '_statusCDLR'
WHERE
p.post_type = 'shop_order'
AND ( pm.post_id IS NULL OR pm.meta_value <> 1 )
GROUP BY p.ID
PS - General remarks regarding your sql :
When mixing ORs and ANDs, you need to surround the test expressions within parentheses to avoid running into prescedence issues (AND has higher precedence than OR).
you should use explicit JOINs instead of implicit ones.

Related

Subquery returns more than 1 row with a Wordpress postmeta query

I am trying to pull data from a subsite's posts and postmeta tables:
SELECT xyz_8_posts.ID,
(select xyz_8_postmeta.meta_value
from xyz_8_postmeta
inner join xyz_8_posts
on xyz_8_postmeta.post_id = xyz_8_posts.ID
where xyz_8_postmeta.meta_key = 'presentation_title'
AND xyz_8_postmeta.post_id = xyz_8_posts.ID
) as 'Presentation Title'
FROM xyz_8_posts
WHERE xyz_8_posts.post_type = "presenters"
I'm getting a "Subquery returns more than 1 row" error. I don't understand why this is. If I replace xyz_8_posts.ID in the WHERE clause with an actual ID the query returns one title.
You have an extra JOIN where you just want a correlated subquery:
SELECT p.ID,
(select pm.meta_value
from xyz_8_postmeta pm
where pm.post_id = p.ID and
pm.meta_key = 'presentation_title'
) as Presentation_Title
FROM xyz_8_posts p
WHERE p.post_type = 'presenters'

try to count this online user's order which is processing

I want to limit each user to register only one order per day.
To do this, I need to check each user's order before registering whether this user has any 'wp-processing' order or not?
I wrote below MySQL query in PHP, but it doesn't work.
I printed value of '$sql_count_from_status' and try it in phpmyadmin, SQL tab to find the error.
Value of the variable was:
SELECT count(ID) FROM wp_posts p LEFT JOIN wp_postmeta m ON p.ID=m.post_id WHERE p.post_status LIKE 'wc-processing' AND p.post_type LIKE 'shop_order' AND m.meta_key LIKE '_customer_user' AND m.meta_value LIKE '100577';
and showed me zero in phpmyadmin as result. Now I know the query has problem, because I had 'processing order' for user 100577.
function get_orders_count_from_status( $status , $this_user_id){
global $wpdb;
// We add 'wc-' prefix when is missing from order staus
$status = 'wc-' . str_replace('wc-', '', $status);
$sql_count_from_status = "
SELECT count(ID) FROM {$wpdb->prefix}posts p
LEFT JOIN {$wpdb->prefix}postmeta m
ON p.ID=m.post_id
WHERE p.post_status LIKE '$status' AND p.post_type LIKE 'shop_order'
AND m.meta_key LIKE '_customer_user'
AND m.meta_value LIKE '".$this_user_id."';";
return $wpdb->get_var($sql_count_from_status);
}
Here's an example of a plausible query (although counting on a LEFT JOIN is a bit strange):
SELECT count(*)
FROM {$wpdb->prefix}posts p
LEFT
JOIN {$wpdb->prefix}postmeta m
ON m.post_id = p.ID
AND m.meta_key = '_customer_user'
AND m.meta_value = :this_user_id
WHERE p.post_status LIKE :status
AND p.post_type = 'shop_order'

Get only unique post_id when checking 2 column values in different rows of the same post_id?

I have the following MySQL Command:
SELECT CASE WHEN pm.meta_key = 'webinar_date' AND pm.meta_value = '20190521' THEN pm.post_id
ELSE NULL
END AS pm_post_id
FROM wp_postmeta AS pm
WHERE pm.meta_key = 'start_time' AND CAST(pm.meta_value AS TIME) <= '21:05:44'
ORDER BY NULL;
I'm trying to get unique post_id values where webinar_date is 20190521 and time is less than or equal to 21:05:44.
According to this image of the data in the wp_postmeta table, it should return rows, but I am getting all NULL values instead.
What am I doing wrong here with this query?
Effectively your query has an AND condition in it on pm.meta_key, wanting it to be both 'webinar_date' and 'start_time' at the same time to generate any rows with data. That cannot be true so all your rows contain NULL for pm_post_id. You can work around that in a number of ways e.g. with a JOIN:
SELECT pm.post_id
FROM wp_postmeta pm
JOIN wp_postmeta pm2 ON pm2.post_id = pm.post_id AND pm2.meta_key = 'webinar_date' AND pm2.meta_value = '20190521'
WHERE pm.meta_key = 'start_time' AND CAST(pm.meta_value AS TIME) <= '21:05:44'

Multiple Meta_Key Select on on Wordpress database

I've developed a query which selects events from Wordpress. I am using the where clause to select where the meta_value of the meta_key eventstartdate is after today.
The issue I'm having now is, I also want filter on a second meta_value that being from the meta_key '_VenueCity'.
I have tried aliasing the wp_postmeta table and doing a where on the meta_key but I think I'm missing a join.
This is the code that works without my additional code to get it to work. Can any one advise on how I get this to work?
SELECT
`wp_posts`.`ID` AS `EventID`,
`wp_posts`.`post_parent` AS `SeriesID`,
`wp_posts`.`post_title` AS `EventTitle`,
`wp_posts`.`post_content` AS `EventDescription`,
`wp_posts`.`post_excerpt` AS `EventSummary`,
`wp_posts`.`post_name` AS `EventSlug`,
min(`wp_postmeta`.`meta_value`) AS `EventStartDate`,
max(`tribe_event_end_date`.`meta_value`) AS `EventEndDate`,
`wp_posts`.`guid` AS `GUID`
FROM ((`wp_posts`
JOIN `wp_postmeta` ON
(
(`wp_posts`.`ID` = `wp_postmeta`.`post_id`)
))
LEFT JOIN `wp_postmeta` `tribe_event_end_date` ON
(
(
(`wp_posts`.`ID` = `tribe_event_end_date`.`post_id`) AND
(`tribe_event_end_date`.`meta_key` = '_EventEndDate')
)
))
WHERE
(
(`wp_postmeta`.`meta_key` = '_EventStartDate') AND
(`wp_posts`.`post_type` = 'tribe_events') AND
(`wp_posts`.`post_status` = 'publish') AND
(`tribe_event_end_date`.`meta_value` >= CURDATE())
)
GROUP BY
`wp_posts`.`ID`
ORDER BY
`EventStartDate`,
`wp_posts`.`post_date`;
I am not going to write your query for you but I will give an example of how to get multiple postmeta values. The power will be in the where clause to get the right values.
You should also consider what joins you want to use.
SELECT
p.post_title,
pm1.meta_value,
pm2.meta_value
FROM wp_posts as p
INNER JOIN wp_postmeta as pm1
ON p.ID = pm1.post_id
INNER JOIN wp_postmeta as pm2
ON p.ID = pm2.post_id
WHERE
pm1.meta_key = '_my_postmeta_field1'
AND
pm2.meta_key <> '_not_this_field'

Advanced MySQL query in Wordpress with JOIN

I am new to MySQL and I am trying to write a quite advanced query. But hey! Learning by doing & Stackoverflow!
I could probably get all data in a less advanced query/queries and sort the data using PHP. But I figure it could be done directly in the query.
Below is my code. Please ask question if you don't understand and I will try to explain better. And please help me correct the code if you find any errors.
The code will be used to display different fields on my wordpress pages. Different fildes will have different categories eg. sidebar-blog, sidebar-page, highlight-blog, highlight-page. It will work almost like regular posts.
Here is the database structure of Wordpress:
http://codex.wordpress.org/images/9/9e/WP3.0-ERD.png
http://codex.wordpress.org/Database_Description
Questions:
How am I supose to join the tables: wp_posts, wp_term_relationships, wp_term_taxonomy, wp_terms AND wp_postmeta?
Is it good practice to make advanced queries or should you use PHP to handle if/else functions?
<?php
$id = $post->ID; // Gets the ID of current page
$query = "
SELECT wp_posts.post_content, wp_posts.ID, wp_terms.slug # Data from two different tables
FROM wp_posts
# Cant figure out how to join the tables
INNER JOIN wp_postmeta
ON wp_posts.ID = wp_postmeta.post_id
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_term_taxonomy.term_id = wp_terms.term_id
WHERE
wp_posts.post_type = 'my-own-post-type' # Only get specific post-type
AND
wp_posts.post_status = 'publish' # Only get published posts
AND
# START - Only get categories specified here
(
wp_terms.slug = 'category-1'
OR
wp_terms.slug = 'category-2'
OR
wp_terms.slug = 'category-3'
OR
wp_terms.slug = 'category-4'
OR
wp_terms.slug = 'category-5'
)
# END - Only get categories specified here
AND
# I want to be able to include or exclude specific pages, even if category is the right one
# Exlude = Don't get data if current page ID is found (ID of current page will be checked in meta_value using %,$id,%)
# Include means: If include value is specifyed, then get data ONLY if ID is found (ID of current page will be checked in meta_value using %,$id,%)
# If not exclude and include are set, it should get the data
# START - Include exclude
(
# exclude is set, so check if page id match anywhere. If it IS found it it should not get the data, otherwise YES
wp_postmeta.meta_key = 'exclude' AND wp_postmeta.meta_value <> '%,$id,%'
OR
# include is set, so check if page id match anywhere. If it IS NOT found it it should not get the data, otherwise YES
wp_postmeta.meta_key = 'include' AND wp_postmeta.meta_value = '%,$id,%'
OR
# If exclude and include aren't set it should get the data
wp_postmeta.meta_key <> 'exkludera' AND wp_postmeta.meta_key <> 'include'
)
# END - Include exclude
";
$result = mysql_query($query);
while($row = mysql_fetch_array($result))
{
// collect all fields in category 1 (eg. sidebar)
if($row['slug'] == 'category-1'){
$all_fields_from_category_1 = $all_fields_from_category_1.'
<div id="field-sidebar">
'.$row['post_content'].'
</div>
';}
// collect all fields in category 1 (eg. highlight)
if($row['slug'] == 'category-2'){
$all_fields_from_category_2 = $all_fields_from_category_2.'
<div id="field-highlight">
'.$row['post_content'].'
</div>
';}
} // end while
// sidebar
echo '<div id="container-sidebar">'.
$all_fields_from_category_1.
'</div>';
// highlight
echo '<div id="container-highlight">'.
$all_fields_from_category_1.
'</div>';
?>
New version, new question:
SELECT DISTINCT wp_posts.post_content, wp_posts.ID, wp_terms.slug
FROM wp_posts
JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
JOIN wp_terms ON wp_term_taxonomy.term_id = wp_terms.term_id
WHERE wp_posts.post_type = 'my-own-fields'
AND wp_posts.post_status = 'publish'
AND wp_terms.slug IN
('field1', 'field2', 'field3', 'field4', 'field5', 'field6')
AND
(
wp_postmeta.meta_key = 'exlude' AND wp_postmeta.meta_value <> '$id'
OR wp_postmeta.meta_key = 'include' AND wp_postmeta.meta_value = '$id'
OR wp_postmeta.meta_key <> 'exlude' AND wp_postmeta.meta_value <> 'include' #LAST ROW
)
The "#LAST ROW" gives me back data even if exclude or include is set. Thats becauce it matches two other rows in the table wp_postmeta.
Example of table wp_postmeta:
meta_id post_id meta_key meta_value
1 30 include 18
2 30 _edit_lock 1322225789:1
3 30 _edit_last 1
If meta_key inklude or exclude cant be found for the post_id I want to return the data...
Example senario when I want to return the data:
meta_id post_id meta_key meta_value
2 30 _edit_lock 1322225789:1
3 30 _edit_last 1
Any idea of how I can solve this?
A statement that say: If no rows with exclude or include was found for current id. Return the data.
More examples:
The post_id is 30.
If senario is:
meta_id post_id meta_key meta_value
1 30 include 18
2 30 _edit_lock 1322225789:1
3 30 _edit_last 1
Then I want to get back wp_posts.post_content, wp_posts.ID and wp_terms.slug AS LONG AS $id IS 18.
If senario is:
meta_id post_id meta_key meta_value
1 30 exclude 18
2 30 _edit_lock 1322225789:1
3 30 _edit_last 1
Then I want to get back wp_posts.post_content, wp_posts.ID and wp_terms.slug AS LONG AS $id IS NOT 18.
If senario is:
meta_id post_id meta_key meta_value
2 30 _edit_lock 1322225789:1
3 30 _edit_last 1
Then I want to get back wp_posts.post_content, wp_posts.ID and wp_terms.slug.
Your joins are done correctly. When removing your comments and extra lines, you will see that the query is not really that complicated. The only real change I made was to change your list of OR for wp_terms.slug to an IN statement. This was only done to reduce code duplication, clean up the look, not to change functionality.
SELECT p.post_content, p.ID, t.slug
FROM wp_posts AS p
INNER JOIN wp_postmeta AS pm ON p.ID = pm.post_id
INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id
INNER JOIN wp_term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN wp_terms AS t ON tt.term_id = t.term_id
WHERE p.post_type = 'my-own-post-type'
AND p.post_status = 'publish'
AND t.slug IN
('category-1', 'category-2', 'category-3', 'category-4', 'category-5')
AND
(
( pm.meta_key = 'exclude' AND pm.meta_value <> '$id' )
OR ( pm.meta_key = 'include' AND pm.meta_value = '$id' )
OR ( pm.meta_key <> 'exclude' AND pm.meta_value <> 'include' )
)