Mysql 'match against' with multiple criteria - mysql

How to compare records from one column with 'match against'? That code is not working properly:
$sql = 'SELECT * FROM `database` WHERE MATCH (`content` WHERE `id` != \'\')AGAINST (`content` WHERE `id` = \'\' IN BOOLEAN MODE)';
$p = $db->query($sql);

As documented, the MATCH() syntax is like this:
MATCH (col1,col2,...) AGAINST (expr [search_modifier])
And is described as:
MATCH() takes a comma-separated list that names the columns to be searched. AGAINST takes a string to search for, and an optional modifier that indicates what type of search to perform. The search string must be a string value that is constant during query evaluation. This rules out, for example, a table column because that can differ for each row.
So, the syntax you have used is completely invalid.

I'm not sure of what you're asking for. Someone else has provided a pretty good response to a similar question posted in the following link:
Mysql search for string and number using MATCH() AGAINST()
Again it seems to me that you are trying to match patterns/expressions between 2 columns from 2 different tables, if I have understood your example correctly. If so, then maybe the solution provided in the link isn't 'the way to go'. It's up to you, hope it helps..

Related

SQL replace function with MATCH() AGAINST()

I would like to use the replace function inside a match function, to remove \n characters before it searches matching rows. Otherwise, for example, if the text is FULLTEXT\nsearch, and the search is search, it will not match.
Here is my query (simplified) :
SELECT * FROM messages WHERE MATCH(REPLACE(body,'\\n',' ')) AGAINST ('mysearch' IN BOOLEAN MODE)
But it throws an error...
[EDIT]
After #Shadow 's answer, I tried this :
SELECT * FROM (SELECT REPLACE(body,'\\n',' ') AS rb FROM messages) AS rbody WHERE MATCH(rb) AGAINST ('mysearch');
I think the idea is correct, but I get an error ERROR 1210 (HY000): Incorrect arguments to MATCH. I think this is because I didn't index the column rb (FULLTEXT INDEX (rb)), so the MATCH () AGAINST () operation won't work.
So I update my question : How can one index a column of a subquery
The answer is that you cannot dynamically remove \n character sequence within a match() call. As MySQL manual on match() says:
MATCH() takes a comma-separated list that names the columns to be searched.
You either have to store \n differently, not as a character sequence or you need to have a separate field in which these characters are already filtered out and this additional field is used for fulltext searches.
Actually, waiting for a better solution, I will just add a column raw_body to my table, where I will store the exact body (I won't escape it with real_sacpe_string, I will just manually replace " and ' by \" and \'), and I will prepare the query and bind the params. However, I don't know if it is secure enough against sqlinjection.
[UPDATE]
Actually I found out that I didn't even needed to manually escape quotes, since the prepared statement is enough to prevent sqli. So I think I will just keep this solution for the moment

MySQL MATCH() AGAINST() with reversed parameters

I have a database table that looks a bit like this:
id|words|url
1|+Word +Matching -Goodbye|/url-1
2|+Redirect +Me|/url-2
3|+Goodbye +Word|/url-3
When a user types a search for: "Hello I am matching a word", I would like the table.words field to be given a 'relevance' score against that string, a lot like the MATCH() AGAINST() function, but with the parameters reversed.
Effectively, the query I am looking to run would be along the lines of:
SELECT id, words, url,
MATCH ("Hello I am matching a word") AGAINST (words IN BOOLEAN MODE) AS relevance
FROM table
ORDER BY relevance DESC
But this does not work, unfortunately. I could do something in PHP where I create a function to loop through each inclusive/exclusive word, but I fear that this will be really slow when the table size grows.
Just to tie it up, I would expect the query to return id: 1 in that instance, as it includes "Word" and 'Matching", and does not include "Goodbye". I should point out that these words could be in any order within the string, so I couldn't really use LIKE, I don't think.
If such a function does not exist, is there a better way I could approach this?
Thanks!
The documentation is pretty clear:
The search string must be a string value that is constant during query
evaluation. This rules out, for example, a table column because that
can differ for each row.
Hence, you cannot do what you want with a query.
You can use dynamic SQL. Or a loop in PHP to loop through the patterns in your table.

search the inbetween string using sql query

In wp_postmeta table meta_value contains the value http/google.co.in/
If the user searches for http/google.co.in/testing, then the resultset should contain http/google.co.in/
I tried with following query:
SELECT * FROM wp_postmeta WHERE meta_value LIKE '%http/google.co.in/testing%'
but it did not return the expected result.
How can i get the desired result? How can I use regular expressions to get this result?
if you use sql: .....LIKE '%http/google.co.in/testing%', then DB will look for any string containing "http/google.co.in/testing". Note that your desired result does not contain "testing" inside.
Let's try:
SELECT * FROM wp_postmeta WHERE meta_value LIKE CONCAT('%', SUBSTR('http/google.co.in/testing', 1, 18), '%')
this '%http/google.co.in/testing%' means you are looking for any string that contains 'http/google.co.in/testing' so 'http/google.co.in/' won't return any result because it doesn't contain the string you are looking for.
You can use SUBSTR() to search for a part your string.
As others have pointed out, LIKE searches for strings containing the entire search string (plus any other strings where the %s are), not strings containing a substring of your string. I don't know if there is such a command.
You suggested perhaps regex is your answer. MySQL does in fact have a regex command, which a quick Google search would show you the documentation for here: http://dev.mysql.com/doc/refman/5.7/en/regexp.html
Do you need further help determining your regex, or is this enough?
If you want further help, you'll have to clarify exactly what regex would be searching for, because you'd have to understand the components of your search string to know what will be constant and what will be variable.

MySQL full text search on JSON data

I'm trying to replicate the following LIKE query using a full text search on JSON data;
SELECT * FROM table
WHERE response LIKE '%"prod_id": "foo"%'
AND response LIKE '%"start_date": "2016-07-13"%'
In my database the above query returns 28 rows
This is my attempt:
SELECT * FROM table
WHERE MATCH(response)
AGAINST('+"\"prod_id\": \"foo\"",+"\"start_date\": \"2016-07-13\""')
However this returns over 4,500 rows (the same as running the first query for only the prod_id ~1,900 rows when running the first query on just the date)
It was my understanding that +"text here" would indicate a required word, and that literal double quotes (present in the JSON data) should be escaped, and that , would indicate a split between the two strings I'm looking for. What am I not understanding correctly? Is there any point in running this as a full text query anyway?
Thanks to #Sevle I've tweaked my query like so, and it's returning the correct results;
SELECT * FROM table
WHERE MATCH(response)
AGAINST('+\"prod_id: foo\" +\"start_date: 2016-07-13\"' IN BOOLEAN MODE)
The comma was not helping and I was escaping the wrong characters, and of course I did need IN BOOLEAN MODE to be added. Finally, I removed the double quotes I was searching for in the JSON string.
It may also be worth noting that as I'm using PHP PDO to run this query I also had to make the following tweaks.
Instead of constructing the query like so trying to bind the variables like I normally would;
$query = $db->prepare('...AGAINST('+\"prod_id: :prod_id\" +\"start_date: :start_date\"');
$query->execute(array('prod_id' => 'foo', 'start_date' => '2016-07-13'));
I had to do this, as I found I could not bind variables in full text searches
$sql_against = $db->quote('...AGAINST('+\"prod_id: foo\" +\"start_date: 2016-07-13\"');
$query = $db->prepare("...AGAINST($sql_against IN BOOLEAN MODE)")

Using MySQL LIKE operator for fields encoded in JSON

I've been trying to get a table row with this query:
SELECT * FROM `table` WHERE `field` LIKE "%\u0435\u0442\u043e\u0442%"
Field itself:
Field
--------------------------------------------------------------------
\u0435\u0442\u043e\u0442 \u0442\u0435\u043a\u0441\u0442 \u043d\u0430
Although I can't seem to get it working properly.
I've already tried experimenting with the backslash character:
LIKE "%\\u0435\\u0442\\u043e\\u0442%"
LIKE "%\\\\u0435\\\\u0442\\\\u043e\\\\u0442%"
But none of them seems to work, as well.
I'd appreciate if someone could give a hint as to what I'm doing wrong.
Thanks in advance!
EDIT
Problem solved.
Solution: even after correcting the syntax of the query, it didn't return any results. After making the field BINARY the query started working.
As documented under String Comparison Functions:
Note
Because MySQL uses C escape syntax in strings (for example, “\n” to represent a newline character), you must double any “\” that you use in LIKE strings. For example, to search for “\n”, specify it as “\\n”. To search for “\”, specify it as “\\\\”; this is because the backslashes are stripped once by the parser and again when the pattern match is made, leaving a single backslash to be matched against.
Therefore:
SELECT * FROM `table` WHERE `field` LIKE '%\\\\u0435\\\\u0442\\\\u043e\\\\u0442%'
See it on sqlfiddle.
it can be useful for those who use PHP, and it works for me
$where[] = 'organizer_info LIKE(CONCAT("%", :organizer, "%"))';
$bind['organizer'] = str_replace('"', '', quotemeta(json_encode($orgNameString)));