I have a script:
$friendnotes = mysql_query("SELECT nid,user,subject,message FROM friendnote
WHERE tousers LIKE '%$userinfo[username]%' ");
And the content in the "tousers" table of the database:
Test
Example
User
That script appears to be working well
However, if there is a user called "Test2", it would also display content that has "Test2" in the database where $userinfo[username] is just "Test"
Is there any way to fix that problem? For example (this is just an example, I don't mind if you give another way) make it so that it searches whole lines?
EDIT: I don't think anyone understands, the "tousers" table contains multiple values (seperated by line) not just one, I want it to search each LINE (or anything that works similiar), not row
The condition
tousers LIKE '%Test%'
means that touser contains "Test" at some point, so it is true for "Test","MyTest","Test3","MyTest3", and so on.
If you want only to match the current user, try
... WHERE tousers = '$userinfo[username]'
EDIT If you really want to store multiple names in one column (separated by newlines), you could use a REGEXP pattern like
WHERE tousers REGEXP '(^|\\n)($userinfo[username])($|\\n)'
Be aware to make sure that $userinfo[username] does not contain any regular-expression-like characters ('$', '^', '|', '(', etc.). Also (as mentioned in the comments above) this solution is suboptimal in terms of security/performance/etc: It would be better to model an 1:n-Relationship between the friendnote table and some friendnotes_user table ...
Ok, so it sounds like the tousers field can contain values like 'stuff test option whatever' and 'foo test2 something blah blah', and you want to match the first but not the second. In that case, you need to include the delimiters around your search term. Assuming the search term will always have a space before and either a space or comma after it, you could do something like:
... WHERE tousers LIKE '%[ ]$userinfo[username][ ,]%'
This will encounter problems, however, if your search term can occur at the beginning of the field (no space character before it) or at the end of the field (no delimiter after it). In that case, you might need to have multiple LIKE clauses.
This will work if you remove the % signs, which are what allow for pattern matching.
$friendnotes = mysql_query("SELECT nid,user,subject,message FROM friendnote
WHERE tousers LIKE '$userinfo[username]' ");
But the consensus seems to be that using equals will be faster. See https://stackoverflow.com/questions/543580/equals-vs-like.
So in that case, change to
$friendnotes = mysql_query("SELECT nid,user,subject,message FROM friendnote
WHERE tousers = '$userinfo[username]' ");
Edit - regarding your edit, that is not a really good design. If a user can have multiple "tousers" (ie a one-to-many relationship), that should be represented as a separate table tousers, where each row represents one "touser" and has a foreign key on the user id to match it with the friendnote table. But if you absolutely can't change your design, you might want to match like this:
WHERE tousers LIKE '%$userinfo[username]\n%' ");
ensuring that there is a line break immediately following the username.
From what I understand, you should just use strict comparison:
where tousers = 'whatever'
That is because tousers like %whatever% matches any row, in which the tousers field has 'whatever' anywhere in its content, so it matches 'whatever', '123whatever', 'whatever321' and '123whatever321'. I hope you get the idea.
So you only want to search for exact name matches? If so, just use an = and remove the % wildcards:
$friendnotes = mysql_query("SELECT nid,user,subject,message FROM friendnote
WHERE tousers = '$userinfo[username]' ");
This is a perfect usage case for the MySQL REGEXP operator.
Related
Here's my use case: I'm searching for a person by first and last name, but only type in a partial first and partial last name, how can I create a WHERE clause that catches all possible scenarios?
Example, I type "Joe Smith" and it has a result. I type "Joe" and it has Joe Smith and a few other Joe's. I type "Joe Sm" and it gives me Joe Smith.
I want to be able to type "J Smit" and get Joe Smith, is that possible? Do I need to break the search term on spaces in PHP before doing a LIKE?
Here's what I have so far that works with full matches:
WHERE CONCAT_WS(' ', owner.first_name, owner.last_name)
LIKE '%". $searchTerm ."%'
Any help would be greatly appreciated.
Why don't you do an explode(' ',$input) on your input in PHP and then compare all values of that array in your WHERE clause?
$inputArray = explode(' ',$input);
foreach ($inputArray as $part)
{
$whereArray = "CONCAT_WS(' ',owner.first_name,owner.last_name) LIKE '%$part%'";
}
$where = implode(' AND ',$whereArray);
And then use it like this:
$query = "SELECT * FROM owner WHERE $where";
Please pay attention to security, I didn't do that.
This still doesn't quite do what you want. Because when you want to search for "J Smit" you want the system to be intelligent enough, to search one part, say "J" in the first name column and the other part "Smit" in the last name column. Clearly that's more complex, and the complexity increases with the number of parts to match. There is a solution for that, but you won't like it, it's ugly.
Has anybody got a, not so ugly, solution to this?
It sounds like you do want split the search term into a first and last name component, and then run LIKE comparisons against owner.first_name and owner.last_name separately. Unfortunately, I don't know of native mySQL support for straightforward string splitting.
Splitting in PHP first is certainly an option (the answer from #KIKOSoftware seems to do a good job of that). If you want to try to do it all in mySQL as an alternative, this SO question offers some insight (you will have to modify for your use case, since you're delimiting on white space instead of commas):
How to split the name string in mysql?
I'm working for the first time with MATCH...AGAINST in php sql but there is one bothering me and I can't figure out how to fix it. This is my code:
SELECT * FROM m_artist WHERE match(artist_name) against('". $_POST['article_content'] ."' IN BOOLEAN MODE)
And this is $_POST['article_content']:
Wildstylez Brothers Yeah Frontliner Waveliner
Now my output should be: Wildstylez, Frontliner and Waveliner cause that's in my database. And I do but besides that I also get the Vodka Brothers, 2 Brothers of Hardstyle and more cause of the word brothers. How do I fix that SQL only selects the literal match?
Full-text search actually is a quite misleading name: you can search the full text by your query (like google does) but it won't guarantee you, that the full text equals your query.
So, according to documentation on Boolean Full-Text Searches your input Wildstylez Brothers Yeah Frontliner Waveliner is interpreted as artist_name contains (at least) one of Wildstylez, Brothers, Yeah, Frontliner and Waveliner as word. This is why you get e.g. the Vodka Brothers, which contains Brothers. For google-like purposes this is just what you want, as you want to get details on something you only know part of as in show me articles on music.
You probably want to use
artist_name LIKE '%name_part1%' OR artist_name LIKE '%name_part2%' ...
or
artist_name IN ('exact_name1', 'exact_name2', ...)
simpliest case would be doing something like
$names = explode(' ', $_POST['article_content']);
$name_searches = array_map(function($a) {return 'artist_name = \''.mysql_real_escape_string($a).'\'';}, $names);
$sql = "SELECT * FROM m_artist WHERE ".implode(" OR ", $name_searches);
but you would loose the ability to find 2 Brothers of Hardstyle as the name itself contains a space.
Another approach can be to prefix all words by '+' and stick to MATCH() AGAINST() and you will find only artists which include every word given.
Please provide more context if this is not what you are looking for.
I've imported a .txt database in MySQL through "LOAD DATA INFILE", and everything seemed working, the only problem is that if I search a record on the DB with the following query:
"SELECT * FROM hobby WHERE name LIKE 'Beading'"
it returns 0 rows, while if I use
""SELECT * FROM hobby WHERE name LIKE '%Beading%'"
it returns 1 row, even if exist one record with name=Beading. Does anybody know what could it depend on?
When using SQL LIKE:
You should use a wildcard identifier such as (or not):
'%word' - return results that the value ends with the letters: "word".
'word%' - return results that begin with the letters: "word".
%word% - return results that include the letters: "word" anywhere.
there are some more pattern search combination like:
'abc' LIKE 'abc' true
'abc' LIKE 'a%' true
'abc' LIKE 'b' true
'abc' LIKE 'c' false
If you want an exact match you should use:
"SELECT * FROM hobby WHERE name='Beading'"
But LIKE 'Beading' should also work, so it's probably a spaces issue or case sensitivity problem.
You need to take care of collation case (sensitivity) when you want to make sure your results are complete.
Say your table is UTF...CS and you want to make an insensitive case search you should declare it in your SQL query, for example:
SELECT * FROM hobby WHERE name COLLATE UTF8_GENERAL_CI LIKE 'beading'
try testing different approaches and see what fits your goal best.
the first one doesnt work because Like statment you should use '%search word%'
you should use this one
"SELECT * FROM hobby WHERE name LIKE '% Beading %' or name LIKE '% Beading'
or name LIKE 'Beading %' or name LIKE 'Beading'"
I have two questions regarding my script and searching. I have this script:
$searchTerms = explode(' ', $varSearch);
$searchTermBits = array();
foreach($searchTerms as $term){
$term = trim($term);
if(!empty($term)){
$searchTermBits[] = "column1 LIKE '%".$term."%'";
}
}
$sql = mysql_query("SELECT * FROM table WHERE ".implode(' OR ', $searchTermBits)."");
I have a column1 with a data name "rock cheer climbing here"
If I type in "rock climb" this data shows. Thats perfect, but if I just type "Rocks", it doesn't show. Why is that?
Also, How would I add another "column2" for the keyword to search into?
Thank you!
Searching that string for "rocks" doesn't work, because the string "rocks" doesn't exist in the data. Looking at it, it makes sense to you, because you know that the plural of "rock" is "rocks", but the database doesn't know that.
One option you could try is removing the S from search terms, but you run into other issues with that - for example, the plural of "berry" is "berries", and if you remove the S, you'll be searching for "berrie" which doesn't get you any further.
You can add more search terms by adding more lines like
$searchTermBits[] = "column1 LIKE '%".$term."%'";
and replacing ".$term." with what you want to search for. For example,
$searchTermBits[] = "column1 LIKE '%climb%'";
One other thing to note... as written, your code is susceptible to SQL injection. Take this for example... What if the site visitor types in the search term '; DROP TABLE tablename; You've just had your data wiped out.
What you should do is modify your searchTermBits[] line to look like:
$searchTermBits[] = "column1 LIKE '%" . mysql_real_escape_string($term) . "%'";
That will prevent any nastiness from harming your data.
Assuming the data you gave is accurate, it shouldn't match because you're using "Rocks" and the word in the string is "rock". By default mysql doesn't do case sensitive matching, so it's probably not the case.
Also, to avoid sql injection, you absolutely should be using mysql_real_escape_string to escape your content.
Adding a second column would be pretty easy as well. Just add two entries to your array for every search term, one for column1 and one for column2.
Your column1 data rock cheer climbing here your search criteria %Rocks% it doesn't fit at all as rocks is not in your column1 data
you can add column2 as you do for column1 then put it all together by using an AND operator (column1 LIKE "%rock%" OR column1 LIKE "%climb%") AND (column2 LIKE "%rope%" OR column2 LIKE "%powder%")
TIPS:
If your table/schema are using xx_xx_ci collation (then this is mean case insensitive,mysql doesn't care case sensitive) but if other then you need to make sure that the search term must be case sensitive(mysql do case sensitive).
I want to search like this: the user inputs e.g. "murrays", and the search result will show both records containing "murrays" and records containing "murray's". What should I do in my query.pl?
What do you think about using the SOUNDEX function and the SOUNDS LIKE operator ?
That way, you can simply do:
SELECT * from USERS WHERE name SOUNDS LIKE 'murrays'
I'm pretty sure it doesn't work for every case, and perhaps it is not the most efficient way to solve the problem, but it could fit your needs.
This won't help if you absolutely need to do these queries in SQL, but if you can set up a Lucene search index for it, you gain a lot of this kind of "fuzzy search" functionality. Note though that Lucene is quite a complex topic by itself.
What you could do is create an extra field in the database, which contains the data with all special characters stripped from it, and search there. A bit lame, I know. Looking forward to see smarter answers ;)
Quick and dirty:
SELECT * FROM myTable WHERE REPLACE(name, '\'', '') = 'murrays'
I would first build a search column which has the text without punctuation and then search on that. Otherwise you'll have have to have a series of regular expressions to search against or check individual records in PHP for matching: both of which are computational intensive operations.
Maybe something like this: (untested!)
SELECT * FROM users WHERE REPLACE(user_name, '\'', '') = "murrays"
If this is for single word searching, you could try using Soundex or Metaphone functions? These would handle sounds-like as well as spelling
Not sure if MySQL has these, but PHP does (which would require separate columns to hold these values).
Otherwise, Richy's no-punctuation extra column seems best.
You could try adding a replace to your query like this
replace(name, '''','')
to temporarily get rid of the apostrophes for the match.
select name from nametable where name = replace(name,'''','');
This query should be able to pick up "murrays" or "murray's".
var inputStr = "murrays";
inputStr = String.Replace("'", "\'", inputStr);
SELECT * FROM ATable WHERE Replace(AField, '\'', '') = inputStr OR AField = inputStr
strip user input and names in database from all non-letter characters.
Use levenstein distance or soundex to find murrays with murray or marrays. This is optional but your users would love that.