Find a specific data from MySQL with PHP - php

I have a user table with column ID and names. All of the ID's data starts with KM followed by 5 characters of number for example KM00001 (7 characters total). I want to make a search query where if the ID is typed in, it will only search in the ID column and if not it will automatically search in the name column.
if(isset($_POST['find'])) {
$find = $_POST['find'];
$query2 = mysqli_query($condb,"SELECT * FROM students WHERE id LIKE '$find' ");
$query = mysqli_fetch_array($query2);
}

You can use a regular expression to check if the input matches your predetermined ID format, and pick which column to search based on whether that's true or false.
In PHP, the command preg_match is used to check against regular expressions, so your script would look something like this:
if(isset($_POST['find'])) {
$find = $_POST['find'];
if (preg_match('/^KM\d{5}$/i', $find)) {
$column = 'id';
}
else {
$column = 'name';
}
$query2 = mysqli_query($condb,"SELECT * FROM students WHERE $column LIKE '$find' ");
$query = mysqli_fetch_array($query2);
}
(In the regular expression /^KM\d{5}$/i, "KM" are literal characters, \d matches any digit, {5} specifies that we want five digits, bookending that between ^ (beginning of string) and $ (end of string) ensures it only matches if the whole input string is an ID, and the "i" flag at the end makes the search case-insensitive.)

Related

Regular expression, how to add front character with end character

I am using Regular Expressions to code the last characters in an SQL statement, for example the operator - e.g if the SQL statement consist of WHERE keyword LIKE 100, then it must search for LIKE. But now I want to add DISTINCT in front of the field name, for example DISTINCT keyword, in the same regex. I am having difficulties with the front character that must be DISTINCT. Ant help please?
$operator = preg_match("/(^DISTINCT\s)\s(NOT|LIKE|NOT LIKE|\<|\>|\!\=)$/", $field, $matches);
$oplength = strlen($matches[0]);
if(strpos($field, $matches[0])) {
$field = trim(substr($field, 0, -$oplength));
}
else {
$matches[0] = '=';
}

Find most popular strings in a table

I am using MyISAM engine with fulltext indexing for storing a list of strings.
These strings can be a single word, or a sentence.
If I want to know how many times string hello appears in my table, I do
SELECT COUNT(*) Total
FROM String s
WHERE
MATCH (s.name) AGAINST ('hello')
I would like to create a similar report, but for all strings. Result should be a list of TOP-N strings that are the most common in this table (top ones most probably are "the", "a", "to" etc.).
Exact match case is pretty obvious:
SELECT name as String, count(*) as Total
FROM String
GROUP
BY name
ORDER
BY total desc
LIMIT *some number*
But it counts only whole strings.
Is there any way to achieve my desired result?
Thanks.
I guess there is no easy way for this. I would create a "statistic table" for this purpose only. One column for words themselves, one column for the number of occurrences. (Primary key on the first column of course.)
For this with a PL/SQL block scanning all strings, and split them for words.
If the string is not found in the statistic table, you insert a new row.
If the string is found in the statistic table, you increase the value in the second column.
This can run for a pretty long time, but after the first run is ready, you only have to check the new strings on insert, perhaps with a trigger. (Assuming you want to use it not once but regularly.)
Hope this helps, I have no simpler answer.
i think if you use the LIKE command will works
select name, count(*) as total from String where name like '%hello%' group by name order by total
let me know
I didn't find any solution with SQL and my Full text index, but I managed to get my desired result by getting all of my strings from DB and processing them on the backend with php:
//get all strings from DB
$queryResult = $db->query("SELECT name as String FROM String");
//Combine all of them into array
while($row = $queryResult->fetch_array(MYSQLI_ASSOC)) {
$stringArray[] = $row['String'];
}
//"Glue" all these strings into one huge string
$text = implode(" ", $stringArray);
//Make everything lowercase
$textLowercase = strtolower($text);
//Find all words
$result = preg_split('/[^a-z]/', $textLowercase, -1, PREG_SPLIT_NO_EMPTY);
//Filter some unwanted words
$result = array_filter($result, function($x){
return !preg_match("/^(.|the|and|of|to|it|in|or|is|a|an|not|are)$/",$x);
});
//Count a number of occurrence of each word
$result = array_count_values($result);
//Sort
arsort($result);
//Select TOP-N strings, where N is $amount
$result = array_slice($result, 0, $amount);

PHP SQL ignore all characters before "-" like statement

I'm trying to select a mssql row however I want to ignore the characters in a certain column before a certain character.
This is the column format:
|5555-55555|
I want to ignore everything before the dash "-" and only see if my variable $search shows up after. Then that's the row I want. I would prefer if it was an exact match. Is this possible or do I have to create a new column with just the number after the dash?
$search = '55555'
$query .= "WHERE '$columnName' LIKE '%$search%'";
Will match any *-55555
$search = '55555';
$query .= "WHERE '$columnName' LIKE '%-$search'";

Word Finder regular expression, PHP & mySQL

I have a query that I'm trying to run against a database of words. The query must return a word that contains another word, and letters given. It is in PHP and mySQL.
For example:
Word Given: Cruel
Letters Given: abcdty
In the database, I need to find the word "Cruelty" based on the letters given, and the word given. It needs to works both ways. So if I had "atni" for letters, "Anticruel" would appear if it existed in the database.
I have it half working but the result given is not correct:
SELECT word
FROM words
WHERE LOCATE( "cruel", word ) >0
AND word != "cruel"
AND word
REGEXP '[ybilteh]'
The result set from this query:
"anticruelty"
"crueler"
"cruelest"
"crueller"
"cruellest"
"cruelly"
"cruelness"
"cruelnesses"
"cruelties"
"cruelty"
Update!!!
Thanks to Benjamin Morel, this is getting much closer.
This query:
SELECT word
FROM words
WHERE LOCATE( "t", word ) >0
AND word != "t"
AND word
REGEXP '^[ybilteh]*t[ybilteh]*$'
LIMIT 0 , 30
Finds words correctly. But also includes words with double letters. Such as "Beet". When only 1 "e" is available.
Try this one:
SELECT word
FROM words
WHERE word REGEXP '^[ybilteh]*cruel[ybilteh]*$'
AND word != 'cruel';
UPDATE: let's go refining with PHP, what about this?
$word = 'cruel';
$letters = 'ybilteh';
$items = array("anticruelty", "crueler", "cruelest",
"crueller", "cruellest", "cruelly", "cruelness",
"cruelnesses", "cruelties", "cruelty");
$letters = str_split($letters);
foreach ($items as $item) {
$list = $letters;
// remove the original word (once)
$thisItem = preg_replace("/$word/", '', $item, 1);
for ($i=0; $i<strlen($thisItem); $i++) {
$index = array_search($thisItem[$i], $list);
if ($index === false) {
continue 2; // letter not available
}
unset($list[$index]); // remove the letter from the list
}
echo "$item\n"; // passed!
}
Returns: cruelly, cruelty
You might probably find a better/simpler approach, but that should do the trick!

Compare words, also need to look for plurals and ing?

I have two list of words, suppose LIST1 and LIST2. I want to compare LIST1 against LIST2 to find the duplicates, but it should find the plural of the word as well as ing form also. For example.
Suppose LIST1 has word "account", and LIST2 has words "accounts,accounting" When i do compare the result should show two match for word "account".
I am doing it in PHP and have the LIST in mysql tables.
You can use a technique called porter stemming to map each list entry to its stem, then compare the stems. An implementation of the Porter Stemming algorithm in PHP can be found here or here.
What I would do is take your word and compare it directly to LIST2 and at the same time remove your word from every word your're comparing looking for a left over ing, s, es to denote a plural or ing word (this should be accurate enough). If not you'll have to generate an algorithm for making plurals out of words as it not as simple as adding an S.
Duplicate Ending List
s
es
ing
LIST1
Gas
Test
LIST2
Gases
Tests
Testing
Now compare List1 to List2. During the same loop of comparison do a direct comparision to items and one where the word, from list 1, is removed from the current word you're looking at in list 2. Now just check is this result is in the Duplicate Ending List.
Hope that makes sense.
The problem with that is, in English at least, plurals are not all standard extensions, nor are present participles. You can make an approximation by using all words +'ing' and +'s', but that will give false positives and negatives.
You can handle it directly in MySQL if you wish.
SELECT DISTINCT l2.word
FROM LIST1 l1, LIST l2
WHERE l1.word = l2.word OR l1.word + 's' = l2.word OR l1.word + 'ing' = l2.word;
This function will output the plural of a word.
http://www.exorithm.com/algorithm/view/pluralize
Something similar could be written for gerunds and present participles (ing forms)
You might consider using the Doctrine Inflector class in conjunction with a stemmer for this.
Here's the algorithm at a high level
Split search string on spaces, process words individually
Lowercase the search word
Strip special characters
Singularize, replace differing portion with wildcard ('%')
Stem, replace differing portion with wildcard ('%')
Here's the function I put together
/**
* Use inflection and stemming to produce a good search string to match subtle
* differences in a MySQL table.
*
* #string $sInputString The string you want to base the search on
* #string $sSearchTable The table you want to search in
* #string $sSearchField The field you want to search
*/
function getMySqlSearchQuery($sInputString, $sSearchTable, $sSearchField)
{
$aInput = explode(' ', strtolower($sInputString));
$aSearch = [];
foreach($aInput as $sInput) {
$sInput = str_replace("'", '', $sInput);
//--------------------
// Inflect
//--------------------
$sInflected = Inflector::singularize($sInput);
// Otherwise replace the part of the inflected string where it differs from the input string
// with a % (wildcard) for the MySQL query
$iPosition = strspn($sInput ^ $sInflected, "\0");
if($iPosition !== null && $iPosition < strlen($sInput)) {
$sInput = substr($sInflected, 0, $iPosition) . '%';
} else {
$sInput = $sInput;
}
//--------------------
// Stem
//--------------------
$sStemmed = stem_english($sInput);
// Otherwise replace the part of the inflected string where it differs from the input string
// with a % (wildcard) for the MySQL query
$iPosition = strspn($sInput ^ $sStemmed, "\0");
if($iPosition !== null && $iPosition < strlen($sInput)) {
$aSearch[] = substr($sStemmed, 0, $iPosition) . '%';
} else {
$aSearch[] = $sInput;
}
}
$sSearch = implode(' ', $aSearch);
return "SELECT * FROM $sSearchTable WHERE LOWER($sSearchField) LIKE '$sSearch';";
}
Which I ran with several test strings
Input String: Mary's Hamburgers
SearchString: SELECT * FROM LIST2 WHERE LOWER(some_field) LIKE 'mary% hamburger%';
Input String: Office Supplies
SearchString: SELECT * FROM LIST2 WHERE LOWER(some_field) LIKE 'offic% suppl%';
Input String: Accounting department
SearchString: SELECT * FROM LIST2 WHERE LOWER(some_field) LIKE 'account% depart%';
Probably not perfect, but it's a good start anyway! Where it will fall down is when multiple matches are returned. There's no logic to determine the best match. That's where things like MySQL fulltext and Lucene come in. Thinking about it a little more, you might be able to use levenshtein to rank multiple results with this approach!

Categories