SEARCH PHP and MYSQL - php

I need mysql code or php to handle some search query
Lets say we have these 5 items in our store.
ID | TYPE | Pattern
1. | Kilner | scissor
2. | Kilner | forcep
3. | Boyd | scissor Small
4. | Boyd | scissor large
5. | Boyd | forcep
6. | Boyd | clamp
Could you help me mysql query to handle below operation
If we search 'boyd' then numbers 3 4 5 and 6 should come up.
If we search 'scissor' then numbers 1 3 and 4 should come up.
If we search 'boyd scissor', numbers 3 and 4 should come up.
If they search' Kilner scissor' then only no 1 should display.
Let me know
thanks

the way to do it in mysql is full text search
SELECT *, MATCH(field) AGAINST ('word1 word2 word3') AS score
FROM table
WHERE MATCH(field) AGAINST('word1 word2 word3')
look this tutorial http://devzone.zend.com/26/using-mysql-full-text-searching/

try this query
SELECT * FROM `table` WHERE `name` LIKE '%$search_var%'
PDO structure
$db = $this->pdo->prepare("SELECT * FROM `table` WHERE `name` LIKE :mysearch");
$db->execute( array("mysearch"=>'%'.$mysearch.'%') );

The query you ask is a bit complex. You want to return matches in both columns, but if both columns match, then single matches have to be discarded.
This means, one way or another, run a query requiring two matches and one requiring one match, comparing the results and returning the appropriate set.
Performance-wise, I believe it is better to run one query that will fetch both, and then handle the results in PHP (you could handle them in MySQL through the use of a superquery).
So:
// We split keywords
$keywords = array_unique(preg_split('/\s+/', $search));
$inset = array();
foreach($keywords as $keyword)
$inset[] = "'".mysql_real_escape_string($keyword)."'";
$sql_in = '('.implode(',', $inset).')';
$query = "SELECT *, IF(type IN $sql_in, 1,0)+IF(pattern IN $sql_in,1,0) AS matches FROM mytable WHERE (type IN $sql_in) OR (pattern IN $sql_in) ORDER BY matches DESC;";
The above uses the discouraged mysql_ functions. Using PDO, that would be:
$keywords = array_unique(preg_split('/\s+/', $search));
// Generate a (?,?,?..?) template as long as $keywords
$sql_in = '('.implode(',', array_fill(0, count($keywords), '?')).')';
$query = "SELECT *, IF(type IN $sql_in, 1,0)+IF(pattern IN $sql_in,1,0) AS matches FROM mytable WHERE (type IN $sql_in) OR (pattern IN $sql_in) ORDER BY matches DESC;";
$st = $db->prepare($query);
$st->execute($keywords);
Note that the above uses exact match, so "Boyd" will retrieve a match with "Boyd", but "Boy" won't. Use the % matching character to change this behaviour.
Now we retrieve a table which is identical to MyTable but has one extra column, "matches", containing either 2 or 1. Can't contain 0 because of the WHERE limitation: one of the two matches must be true and count as 1.
The 2's will be returned first, so we can do
if (!isset($matches))
$matches = $tuple['matches'];
else
if ($tuple['matches'] < $matches)
break;
that is, we save the first (and highest) value, and only accept that value for the subsequent tuples. As soon as an inferior match comes by, we exit the loop and close the cursor.
This may be done in MySQL with
SELECT * FROM ( the above query ) AS newTable
WHERE matches = (
SELECT MAX(matches) FROM ( the above query ) AS tmpTable
);
but it incurs a performance penalty.

$search=array('byod','scissor');
$st=""; $st2="";
foreach($search as $value){$st.="type=%$value% or ";$st2.="pattern=%$value% or ";}
$st2=substr($st2,0,-3);
echo "select * from tablename where $st $st2";

Related

How to add not existing record and return it with zero value in Mysqli

QUERY:
SELECT month(date_created), count(a.ticket_num)
FROM ticket as a
LEFT JOIN user_management as b on b.engineer_id = a.ticket_engineer
WHERE b.tl_id = 'sample_id'
AND year(date_created) = '2019'
GROUP BY extract(year from date_created), extract(month from date_created)
SAMPLE OUTPUT:
month | ticket_num
----------------------
2 | 12
4 | 24
6 | 78
EXPECTED SAMPLE OUTPUT:
month | ticket_num
----------------------
1 | 0
2 | 12
3 | 0
4 | 24
5 | 0
6 | 78
As you can see the above expected output, i'm trying to place all existing month in the first column and set all the count to zero if not existed in the second column. As of now, i only have the query for sorting the ticket count by month that is existed when the ticket is created.
There are different approaches to this problem. One is pure SQL for example.
But I would say a PHP based solution is simpler. Basically you need to get your data into array, then create a loop that outputs the desired months order, and have a condition that sees whether we have a corresponding row in our array and outputs ether the actual data or a zero accordingly.
The only tricky part is to have such an array that would let us check the data availability. For this we have to index it with month numbers. Not a big deal actually
$sql = "SELECT month(date_created), count(a.ticket_num) ...";
$res = $mysqli($sql);
$data = [];
while($row = mysqli_fetch_row($res)) {
$data[$row[0]] = $row[1];
}
Now $data is an array indexed by the month number. The rest is a primitive loop
foreach (range(1,12) as $month) {
echo $data[$month] ?: 0;
}
On a side note I would like to advertise using PDO as opposed to mysqli for your database interactions as this case clearly displays the superiority of the former. Using PDO we can get the indexed array right away, without an explicit loop, thanks to a special fetch mode:
$sql = "SELECT month(date_created), count(a.ticket_num) ...";
$data = $data = $pdo->query($sql)->fetchAll(PDO::FETCH_KEY_PAIR);
That's all!

PHP remove specific numbers from MySQL field

My db is structured like:
id | posts | groups
----+--------+-----------
1 | 10 | 2
2 | 30 | 2
3 | 20 | 2
4 | 50 | 2,8
5 | 54 | 2,8
When a user gets to 50 or more posts I want the script to remove the group '2'. There is already a prior script that adds the '8'.
I have this:
$cusstring = mysql_query("SELECT `groups` FROM `users` WHERE `postnum` >= 50 ");
$row = mysql_fetch_array($cusstring);
$array = explode(',', $row[groups]);
$pos = array_search('2', $array);
unset($array[$pos]);
$row[groups] = implode(',', $array);
mysql_query("UPDATE `users` SET `groups` = $row[groups] WHERE `postnum` >= 50 ");
It just doesn't seem to update though. I don't know if this is because it picks up multiple fields in the array or if I'm doing something wrong with the greater than or equal to symbol.
Can anyone offer a solution?
Thanks.
EDIT:
I've worked out that if I change the symbol to equal to the query works on the first row it comes across with a post count of 50 but it leaves the rest. It would appear it's only able to process one row.
I think this would work for you. I think a SQL approach would be more efficient but you've said you want to keep it in PHP.
$cusstring = mysql_query("SELECT `groups`, `id ` FROM `users` WHERE `postnum` >= 50 ");
while($row = mysql_fetch_array($cusstring)) {
$groups = mysql_real_escape_string(preg_replace('~(^|\s+)2(,|$)~', '', $row['groups']));
//regex demo https://regex101.com/r/eX7qD1/1
$id = (int)$row['id'];
mysql_query("UPDATE `users` SET `groups` = '$groups' WHERE `id ` = $id ");
}
Your code is only getting one record because you aren't looping the fetch.
Also don't put data that comes from your DB back into a query directly this can lead to a SQL injection. Note I cast the ID here to an int and escaped the groups value. This should prevent the possibility of an injection.
You should switch drivers to PDO or MYSQLI. Once using one of those drivers you can use prepared statements.
This solution also will put an empty value in the groups field if 2 was the only value.

MYSQL query closest match from a second table

Hi I have 2 tables structured as follows
cdr
src | bill sec | clean_dst
------------------------------
100 | 10 | 18006927753
100 | 22 | 18006927753
100 | 9 | 441138973356
dialing_codes
id | dial_code | tele2id
-----------------------------
1 | 1 | 1422
2 | 1800 | 1433
3 | 441 | 1024
4 | 4413 | 1086
I need to get the tele2id for the closest match in dial_code against clean_dst my best effort so far is
$query = "SELECT tele2id, dial_code FROM dialing_codes ORDER by dial_code DESC";
$result = $mysqli->query($query) or die($mysqli->error.__LINE__);
while($row = $result->fetch_assoc()) {
$tele2id = $row['tele2id'];
$dialcode = $row['dial_code'];
$query2 = "SELECT clean_dst FROM cdr WHERE clean_dst LIKE '".$dialcode."%'";
$result2 = $mysqli->query($query2) or die($mysqli->error.__LINE__);
while($row2 = $result2->fetch_assoc()) {
Which I thought was working but on closer inspection it only returns the correct result the first time if a clean_dst is repeated
eg
clean_dst dial_code tele2id
18006927753 1800 1433
18006927753 1 1422
What am i doing wrong? Thanks
If it helps I need the result with the most matching digits?
Although not in php, this one sql can handle your first and secondary query all in one... AND properly handle returning the longest matching entry per dial.
select
PQ.clean_dst,
PQ.dial_code,
PQ.tele2id,
#Rank := if( #lastDst = PQ.clean_dst, #Rank +1, 1 ) as dialRank,
#lastDst := PQ.clean_dst as ForNextRowCompare
from
( SELECT distinct
cdr.clean_dst,
dc.dial_code,
dc.tele2id,
length( trim( dc.dial_code )) as Longest
from
cdr
JOIN dialing_codes dc
on cdr.clean_dst like concat( dc.dial_code, '%' )
order by
cdr.clean_dst,
Longest DESC ) PQ,
( select #lastDst := '',
#Rank := 0 ) sqlvars
having
dialRank = 1
The first part is the inner query resulting in alias "PQ" (preQuery). It is getting a list of distinct combinations for any call data record to its matching POSSIBLE dial codes. Critical component is to put the order by each phone number dialed, THEN based on the longest dial code in descending order. This will put your "1800" at the top of the list per phone number using it.
Next comes the outer query where the MySQL #variables are applied. These work like in-line programming loop for you and goes for every record in the "PQ" result set. It starts the variables with blank and zero respectively.
Every record compares its dialed number to the last dialed number record (in cases like your 1800 and 1 multiple return sets). If they ARE the same phone, add 1 to the existing #Rank, otherwise, it is a change in phone numbers... always start a phone number change back to rank 1. THEN, it assigns the #lastDst to the phone number it just processed so it can be the basis of the next phone record being tested.
At the end is a HAVING clause to only include those of DialRank = 1
So, per your record set samples, the query would result in records looking something like...
Dial Number Dial_Code Tele2ID Longest DialRank ForNextRowCompare
18006927753 1800 1433 4 1 18006927753 <-- Keep this
18006927753 1 1422 1 2 18006927753
441138973356 441 1024 3 1 441138973356 <-- Keep this
Feedback per comment. TO handle your update, you can just wrap it up
update cdr,
( full query ) as FromThisQuery
where cdr.clean_dst = FromThisQuery.clean_dst
set tele2id = FromThisQuery.tele2id
Please try this query:
select dial_code, clean_dst from cdr c, dialing_codes d where c.clean_dst
like concat(d.dial_code, '%');
You don't need to code all that logic in php. MySQL gives you the functions and comparisons to do it natively in SQL, which is simpler and much more concise.
Hope this helps.

mysql get many id's on one row

How to get all ids separated by comma on one row.
id | name
1 | Jonny
2 | Lisa
3 | Ben
And with php/mysql get with one query without a loop the ids comma separated. Like "1,2,3"
To be something like this :
$query = "SELECT 1,2,3 as oneRowIds FROM tableName";
$result = mysql_query($query);
$result = mysql_fetch_assoc($result);
echo $result['oneRowIds'];// and that shows "1,2,3"
use group_concat function
GROUP_CONCAT() function is used to concatenate column values into a single string. It is very useful if you would otherwise perform a lookup of many row and then concatenate them on the client end.
select group_concat(id) as oneRowIds FROM tableName

Select rows where column text contains value of an array

I'm building a search function in php/mysql and I'm looking for the right MySql function. My table sort of looks like this:
id | text
--------------------------------------
1 | I like pony's.
2 | Do you like fish?
3 | We like fishes!
I want to search the column 'text' for one of the exact values of an array, for example:
$search_array = array('fish','dogs','cat','panda');
I'm looking for the right MySql function to return only the second row (with the current array). The array can contain hundreds of values.
I have 6000+ rows, growing everyday with +/- 400. I've tried REGEXP but with a large array, it took about 10 seconds before it returned the corresponding rows.
Please help, I'm fighting with this for almost 3 full days now... Thanks in advance!
If the search array is constant, or changes infrequently, I recommend having another two tables, 'tags' and 'tags-text'.
For example, the row with id 2 in your example contains fish, since fish is in our 'tags' table a new record will be placed in a 'tags-text' table. When you are searching with your array, you can search if one of the array components is in the 'tags-text' table, and join the 'text' table and return the text and id and do whatever you need.
Structure of other tables:
'tags' table
id | tags
--------------------------------------
1 | fish
2 | dogs
3 | cats
'tags-text' table
text-id | tags-id
--------------------------------------
2 | 1
Does this help/make sense
Ok I think I've found the easiest solution: let PHP create the mysql query and solve it with WHERE LIKE.
$search_array = array('fish','dogs','cat','panda');
$string = '';
foreach($search_array as $term) {
$string = $string."text LIKE '%".$term."%' AND ";
}
The result of the foreach loop is:
"text LIKE '%fish%' AND LIKE '%dogs%' AND LIKE '%cat%' AND LIKE '%panda%' AND "
Now lets remove the tail of that string and write the query:
$string = substr($string, 0, -5); // removing " AND " at the end of the string
$query = "SELECT * FROM table WHERE $string";
$results = mysql_query($query);
Thanks for the other answers anyway :)
Ok, maybe you should try mixing mysql and php a bit.
Here is the pseudo-code
select 100-1000 rows at one time from db
use strpos to check each element in your array against the text column
if element found
store it
if 2 elements found break the loop
else
continue
Something like this maybe ...
$search_term = implode(",",$search_array);
SELECT * FROM your_table WHERE text IN ($search_term)";

Categories