MYSQL/PHP: How do you Order By Starting point in a string? - php

SELECT
SQL_CALC_FOUND_ROWS posts.*,
CASE
WHEN postmeta.meta_value REGEXP '$regex'
THEN 1
ELSE 0
END AS keyword_in_title,
MATCH ( posts.post_content )
AGAINST ( '".addslashes( $s )."' ) AS mysql_score
FROM
$wpdb->posts as posts,
$wpdb->postmeta as postmeta
WHERE
posts.post_date_gmt <= now()
AND postmeta.post_id = posts.ID
AND postmeta.meta_key='_headspace_page_title'
AND posts.post_password = ''
AND posts.post_status = 'publish'
AND posts.post_type != 'attachment'
AND ( postmeta.meta_value REGEXP '$regex'
OR posts.post_content REGEXP '$regex')
GROUP BY
posts.ID
ORDER BY
charindex($s, 'keyword_in_title') DESC
LIMIT
$offset,
$limit

As to the order issue (Apart from the escaping issue #Gumbo pointed out in the comment), CHARINDEX is not a valid mysql string function. The LOCATE function looks to be identical (at least from a cursory glance between the docs on SQLServer and MySQL)...
$s = mysql_real_escape_string($s);
$order = 'ORDER BY LOCATE(\''.$s.'\', `keyword_in_title`) DESC';

I'm assuming that the code above does not work and hence you're asking a question.
Try adding charindex($s, 'keyword_in_title') AS cOrder in your SELECT clause and then ORDER BY cOrder DESC
Good luck!

Related

WordPress Subquery returns more than 1 row on SELECT

I am executing this query with core cron by custom Wordpress plugin:
// MAKE SQL CALL
$SQL = "SELECT ".$wpdb->prefix."postmeta.post_id FROM ".$wpdb->prefix."postmeta
INNER JOIN ".$wpdb->prefix."posts ON (".$wpdb->prefix."posts.ID = ".$wpdb->prefix."postmeta.post_id )
WHERE ".$wpdb->prefix."postmeta.meta_key = '".$core_admin_values['listing_expiration']['key']."'
AND ".$wpdb->prefix."posts.post_status = 'publish'
AND ".$wpdb->prefix."postmeta.post_id = (SELECT ".$wpdb->prefix."postmeta.post_id FROM ".$wpdb->prefix."postmeta WHERE ".$wpdb->prefix."postmeta.meta_key = 'listing_status' AND ".$wpdb->prefix."postmeta.meta_value != 1)
AND ".$wpdb->prefix."posts.post_type = '".$core_admin_values['listing_expiration']['taxonomy']."_type'
AND DATE(".$wpdb->prefix."postmeta.meta_value) < DATE(NOW())";
$expired_listings = (array)$wpdb->get_results($SQL);
But return this error:
FastCGI sent in stderr: "PHP message: Database error of WordPress Subquery returns more than 1 row for SELECT
How to solve this? I tried some solutions by similar problems here in Stack, but it still fails.
For the sake of legibility I reformatted your query.
SELECT
postmeta.post_id
FROM
postmeta
INNER JOIN posts
ON (posts.ID = postmeta.post_id )
WHERE
postmeta.meta_key = '".$core_admin_values['listing_expiration']['key']."'
AND posts.post_status = 'publish'
AND postmeta.post_id =
(
SELECT
postmeta.post_id
FROM
postmeta
WHERE
postmeta.meta_key = 'listing_status'
AND postmeta.meta_value != 1
)
AND posts.post_type = '".$core_admin_values['listing_expiration']['taxonomy']."_type'
AND DATE(postmeta.meta_value) < DATE(NOW())";
I suspect your issue stems from the subquery in your where clause.
SELECT
postmeta.post_id
FROM
postmeta
WHERE
postmeta.meta_key = 'listing_status'
AND postmeta.meta_value != 1
And that this chunk is returning more than one result. If you want to match against more than one result, change from "=" to "in" like so:
AND postmeta.post_id in
(
SELECT
postmeta.post_id ...
)
try to add LIMIT on subquery
// MAKE SQL CALL
$SQL = "SELECT ".$wpdb->prefix."postmeta.post_id FROM ".$wpdb->prefix."postmeta
INNER JOIN ".$wpdb->prefix."posts ON (".$wpdb->prefix."posts.ID = ".$wpdb->prefix."postmeta.post_id )
WHERE ".$wpdb->prefix."postmeta.meta_key = '".$core_admin_values['listing_expiration']['key']."'
AND ".$wpdb->prefix."posts.post_status = 'publish'
AND ".$wpdb->prefix."postmeta.post_id = (SELECT ".$wpdb->prefix."postmeta.post_id FROM ".$wpdb->prefix."postmeta WHERE ".$wpdb->prefix."postmeta.meta_key = 'listing_status' AND ".$wpdb->prefix."postmeta.meta_value != 1 LIMIT 1)
AND ".$wpdb->prefix."posts.post_type = '".$core_admin_values['listing_expiration']['taxonomy']."_type'
AND DATE(".$wpdb->prefix."postmeta.meta_value) < DATE(NOW())";
$expired_listings = (array)$wpdb->get_results($SQL);
similar problem several years after, but, in my case, I wasn't able to find the query to make the change, so, I decided to remove the warning message (because it was just a warning) and the way that I used for did that was adding this lines to the wp-config.php file:
ini_set('display_errors','Off');
ini_set('error_reporting', E_ALL );
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);
Regards!

How to convert normal sql query to Zend_Db_Select?

Hi I want to convert my normal mysql query to zend.db.select;
I want to use this script:
$select = $db->select();
// Add a FROM clause
$select->from( ...specify table and columns... )
// Add a WHERE clause
$select->where( ...specify search criteria... )
// Add an ORDER BY clause
$select->order( ...specify sorting criteria... );
$select->limit(20, 10);
for my query below
SELECT
IF(derived_messages.toid = '$user', derived_messages.fromid,
derived_messages.toid) friend1,c.UserName,
derived_messages.message, derived_messages.fromid, derived_messages.toid,
derived_messages.is_read,derived_messages.type,derived_messages.id as mesid,
derived_messages.date,
(SELECT M.message_id FROM messagesmapped M where M.message_id= derived_messages.id AND M.user_id ='$user' AND M.important = 1) as MesMapid
FROM
(
SELECT *
FROM messages
WHERE messages.deleted_by NOT
IN ( $user )
ORDER BY Date DESC
) derived_messages
INNER JOIN Users c ON c.MemberID = IF(derived_messages.toid = '$user', derived_messages.fromid,
derived_messages.toid)
WHERE (derived_messages.id IN
(SELECT M.message_id FROM messagesmapped M where M.message_id= derived_messages.id AND M.user_id ='$user' AND M.important = 1)
AND
(derived_messages.toid='$user' OR derived_messages.fromid='$user'))
GROUP BY friend1 ASC
ORDER BY derived_messages.date DESC, derived_messages.id DESC LIMIT $limit $offset
I hope someone can help m on this.
Thank you.
It's possible but unlikely someone will write the query for you.
My recommendation on tackling such a query is to write each individual subquery as its own Zend_Db_Select object and then build the final query using the subqueries that you already have objects for.
Zend_Db_Select doesn't directly support the IF function, so for that you will need to use Zend_Db_Expr to add that statement into your select.
Here is a basic example of what I am talking about. Let's build the following query:
SELECT IF(msg.toId = 'drew010', msg.fromId, msg.toId), id, name, age, history.ip
FROM users
JOIN history ON users.id = history.userId
WHERE users.id = (
SELECT id FROM users WHERE loginCount > 1000
)
GROUP BY id,
ORDER BY age DESC
First build the subselect that select users where loginCount > 1000.
$subquery1 = $db->select()
->from('users', array('id'))
->where('loginCount > ?', 1000);
Next, build the outer query with the IF function:
$cols = array(
new Zend_Db_Expr('IF(' . $db->quoteInto('msg.toId = ?', 'drew010') . '), msg.fromId, msg.toId'),
'id', 'name', 'age'
);
$query = $db->select()
->from('users', $cols)
->join('history', 'users.id = history.userId', array('ip'))
->where('id = ?', $subquery1)
->group('id')
->order('age DESC');
echo $query;
The output:
SELECT
IF(msg.toId = 'drew010', msg.fromId, msg.toId),
`users`.`id`,
`users`.`name`,
`users`.`age`,
`history`.`ip`
FROM `users`
INNER JOIN `history`
ON users.id = history.userId
WHERE id = (
(SELECT `users`.`id`
FROM `users`
WHERE (loginCount > 1000))
)
GROUP BY `id`
ORDER BY `age` DESC
So the way to go is break the entire query into individual queries first, and then construct the outer query. Just have patience and take it slow. That and read over the Zend_Db_Select docs to get a full picture of what you have available to you.

MySQL make query include PHP variable which contains another variable

I have tried several things but I can't get the MySQL query in my php code to work. Note that the query DOES WORK when I hard-code the variable $lastmsg which is an integer.
The code works in two instances:
When the page loads, the query runs, ignoring $pagination because $lastmsg is not set.
A button sends a value for lastmsg to this page, which runs the code again, this time looking at $pagination because lastmsg is set.
Again, the query DOES WORK. The proof being that it runs perfectly fine in the first instance and returns properly when the variables are hard coded. Firebugs reports that lastmsg is being sent by post.
The problem is that the query isn't receiving the value for $lastmsg (I get no values returned). I know this is because $lastmsg is sitting inside $pagination.
P.S. I am aware it needs injection protection... I'm just trying to get this to work:
if(isset($_POST['lastmsg']) &&is_numeric($_POST['lastmsg'])){
$lastmsg = $_POST['lastmsg'];
$pagination = 'AND $wpdb->posts.ID < ".$lastmsg."';
} else {
$pagination = '';
}
$pageposts = $wpdb->get_results($wpdb->prepare("
SELECT * FROM $wpdb->posts
LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
WHERE $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->posts.post_date < NOW()+INTERVAL 1 DAY
AND $wpdb->term_taxonomy.taxonomy = 'category'
AND $wpdb->term_taxonomy.term_id IN(3)
".$pagination."
ORDER BY $wpdb->posts.post_date DESC
LIMIT 10
"), OBJECT);
The following DOES NOT work
$pagination = 'AND $wpdb->posts.ID < ';
$pageposts = $wpdb->get_results($wpdb->prepare("
SELECT * FROM $wpdb->posts
LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
WHERE $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->posts.post_date < NOW()+INTERVAL 1 DAY
AND $wpdb->term_taxonomy.taxonomy = 'category'
AND $wpdb->term_taxonomy.term_id IN(3)
".$pagination."
".$lastmsg."
ORDER BY $wpdb->posts.post_date DESC
LIMIT 10
"), OBJECT);
Any solutions?
This is not the string you're looking for:
$pagination = 'AND $wpdb->posts.ID < ".$lastmsg."';
That will leave a literal AND $wpdb->posts.ID < ".$lastmsg." inside $pagination and that string won't do anything useful when you hand it to MySQL.
You want double quotes on the outside (for interpolation) and no single quotes at all:
$pagination = "AND $wpdb->posts.ID < $lastmsg";
Or, if $lastmsg is a string rather than a number:
$pagination = "AND $wpdb->posts.ID < '$lastmsg'";
That should get your first version working.
Now go forth and add all your mysql_real_escape_string calls.
PHP parser will ignore the lines quoted with single quotes('') as if they are normal strings. You can force PHP parser to parse the strings too by enclosing them inside double quotes ("").
In your case $pagination goes like this
$pagination = 'AND $wpdb->posts.ID < ".$lastmsg."';
Outer quotes are single quotes so it will be ignored by PHP and $wpdb->posts.ID and even $lastmsg will be considered as simple strings, they wont get their PHP values.
just change your string to
$pagination = "AND $wpdb->posts.ID < '$lastmsg'";
again if $lastmsg is numeric you don't need inner quotes

SQL exclude first ID entry

I need to exclude first id entry, and display the rest on my wordpress, I have never used sql before.
$all_users_id = $wpdb->get_col( $wpdb->prepare("SELECT $wpdb->users.ID FROM $wpdb->users ORDER BY %s ASC", $sort ));
One way would be to use something like
SELECT *
FROM Table
WHERE ID > (SELECT MIN(ID) FROM Table)
I am not familiar with Wordpress, but try this:
$all_users_id = $wpdb->get_col( $wpdb->prepare("SELECT $wpdb->users.ID FROM $wpdb->users WHERE $wpdb->users.ID NOT IN (SELECT MIN($wpdb->users.ID) FROM $wpdb->users) ORDER BY %s ASC", $sort ));
$all_users_id = $wpdb->get_col( $wpdb->prepare("SELECT `$wpdb->users.ID` FROM `$wpdb->users` WHERE `$wpdb->users.ID` != 1 ORDER BY %s ASC", $sort ));
The query used:
SELECT `$wpdb->users.ID`
FROM `$wpdb->users`
WHERE `$wpdb->users.ID` != 1
ORDER BY %s ASC
Fast and simple... Without sub-querys! :)
If it's a mysql db then use the limit clause:
SELECT `$wpdb->users.ID`
FROM `$wpdb->users`
ORDER by $sort ASC
LIMIT 1,9999999
C.

MySQL - Skip Duplicate WordPress Entries

I'm writing a script to display the 10 most recently "active" WordPress blog posts (i.e. those with the most recent comments). Problem is, the list has a lot of duplicates. I'd like to weed out the duplicates. Is there an easy way to do this by changing the MySQL query (like IGNORE, WHERE) or some other means? Here's what I have so far:
<?php
function cd_recently_active() {
global $wpdb, $comments, $comment;
$number = 10; //how many recently active posts to display? enter here
if ( !$comments = wp_cache_get( 'recent_comments', 'widget' ) ) {
$comments = $wpdb->get_results("SELECT comment_date, comment_author, comment_author_url, comment_ID, comment_post_ID, comment_content FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT $number");
wp_cache_add( 'recent_comments', $comments, 'widget' );
}
?>
Look at the DISTINCT option for the SELECT statement. Or alternatively the GROUP BY syntax (look at the same link). Though they work in different ways, these would be the two methods most likely to help you get exactly what you want.
I thought I had figured it out using GROUP BY, but now I'm not so sure. Here is the code:
if ( !$comments = wp_cache_get( 'recent_comments', 'widget' ) ) {
$comments = $wpdb->get_results("SELECT comment_post_ID, comment_author, comment_date FROM $wpdb->comments WHERE comment_approved = '1' GROUP BY comment_post_ID ORDER BY comment_date_gmt DESC LIMIT $number");
wp_cache_add( 'recent_comments', $comments, 'widget' );
}
The single change is to add GROUP BY comment_post_ID (the field I wanted to be unique). Unfortunately, this "breaks" the function; it's frozen and does not update.
I also could not get DISTINCT to work. One comment I'm following up on to figure this out came from http://www.webmasterworld.com/forum88/9204.htm
In particular, comment #:1259236 by ergophobe says, "You left out the GROUP BY. Without that, you will get multiple results for a given topic_id b/c the row will not be distinct. In fact, the distinct is not necessary, just the GROUP BY."
Still looking....

Categories