I've got a database search field where I want the user to be able to input simple boolean logic and have that translated to a mySQL search string.
So for instance if the user inputs: (php AND mysql) OR ajax
I'd like to convert that to:
((c.Skillset LIKE '%php%' AND c.Skillset LIKE %mysql%) OR c.Skillset LIKE '%ajax%')
Is there a fairly simple way of doing this? I'm having particular trouble coming up with a solution for the brackets, if it wasn't for that it would be quite straightforward.
The following assumes you have some constant called SQL_PREFIX_STRING defined.
$string = '(php AND mysql) OR java';
preg_match_all('/[a-z]+/', $string, $skills); // puts the skills in an array
$skills = $skills[0]; // shift array to get the matching values
array_walk($skills, function (&$skill) {$skill = '%'.$skill.'%';}); // add wildcards to parameters
$query_string = preg_replace('/[a-z]+/', 'c.Skillset LIKE ?', $string); // create the ? parameters for the SQL string
$pdoStatement = $pdo->prepare(SQL_PREFIX_STRING.$sql); // prepare
$pdoStatement->execute($skills); // execute
Related
How do I separate my array strings delimiter (|) using the implode function of PHP something like the below String
|Java||PHP||Bootstrap||HTML||CSS|
Actually, I am using a double delimiter to differentiate tags like SQL and MySQL because LIKE "%sql%" will return MySQL results as well. Should be LIKE "%|sql|%"
What I have tried:
$array_service_offer = array();
if (isset($_POST['service_offer'])) {
foreach ($_POST['service_offer'] as $selectedOption) {
array_push($array_service_offer, $selectedOption);
}
//$service_offer = implode(',',$array_service_offer);
$service_offer = '|' . implode('||', $array_service_offer) . '|';
} else {
$service_offer = "";
}
First of all, according to #Qirel comment, I would also recommend to use $array_service_offer[] = $selectedOption; instead of array_push($array_service_offer, $selectedOption);
now for separation, there are several solutions.
One solution is that:
1- to remove first and last | character (it is like trimming)
2- to explode the trimmed string using || delimiter
for that you may use the following code:
$service_offer_trimmed = preg_replace("~(^\|)|(\|$)~", "", $service_offer);
$service_offer_array = explode('||', $service_offer_trimmed);
The other solution is to use straight forward preg_replace function to separate the string. the command follows:
$service_offer_array = preg_split("~(^\|)|(\|\|)|(\|$)~", $service_offer, 0, PREG_SPLIT_NO_EMPTY);
And one more professional solution is that to store your data in database in JSON format rather than delimited code and then when you need to search in your database you may use MySql JSON_CONTAINS function rather than LIKE command.
I have not personally made a performance check on both two solutions but if it not a big database, then it is not a big concern as well.
Therefore, you initial code to get the data and store it into the database will be:
$array_service_offer = array();
if (isset($_POST['service_offer'])) {
foreach ($_POST['service_offer'] as $selectedOption) {
$array_service_offer[] = $selectedOption;
}
}
// $json_service_offer will be saved to the database
$json_service_offer = json_encode($array_service_offer);
the manual on how to use JSON_CONTAINS is in the following link:
12.17.3 Functions That Search JSON Values
I've got this code:
function searchMovie($query)
{
$this->db->where("film_name LIKE '%$query%'");
$movies = $this->db->get ("films", 40);
if($this->db->count > 0)
{
return $movies;
}
return false;
}
Javascript code from my submit form button strips all special characters like ; : ' / etc. from query string, and then redirects user to search uri (szukaj/query). So for example if film_name is Raj: wiara, and user searches for raj: wiara, the query looks like raj wiara and user doesn't get any results. I was thinking about exploding query into single words and then foreach word do a SELECT from db, but it would give multiple results of same movie. Don't want to change the javascript code, and I think I can't make that film names without the special characters like :.
Or maybe create another column in db for film_keywords and add there all words of movie separated by , or something and then search this column?
MySQL's Full Text Search functions are your friend here:
http://dev.mysql.com/doc/refman/5.7/en/fulltext-search.html
Will return a series of matches and give a score so you return in best-match order.
Warning: $this->db->where("film_name LIKE '%$query%'"); is open to SQL injection. Anyone can circumnavigate the JavaScript so you must always clean up input server-side. This is best done using the DB functions as well, not just stripping characters - so check whatever library you are using in order to do this.
You could indeed explode your string, using this answer's solution.
function searchMovie($query)
{
$queries = preg_split('/[^a-z0-9.\']+/i', $query);
foreach ($queries as $keyword){
$this->db->where("film_name LIKE '%$keyword%'");
}
$movies = $this->db->get ("films", 40);
if($this->db->count > 0)
{
return $movies;
}
return false;
}
This will create multiple ANDconditions for your db where, so the result will be filtered.
Let's say i check if
$strig = "how can i do this";
already exists in my database with all words order options?
Like:
"how i can do this"
or
"i do this can how"
...
...
my database looks like:
id string
1 how can i do this
2 hello how are you
3 how i can do this world
4 another title
etc etc
Thanks
The number of possible combinations is n! (120 in your sample) so checking if this string already exists is quite complex task.
I would recommend to use the following algorithm:
Add new column StringHash to your table
On insert order your string (e.g. alphabetically), calculate its hash and store in StringHash:
"how can i do this" => "can do how i this" => md5("can+do+how+i+this")
If you want to check if a certain string exists in the db then again calculate its hash as described above and query the db on YourTable.StringHash
This is a tricky problem if you want to fix this in sql only, but that aside:
As #er.anuragjain says, you can do a query with LIKE %word%, but you would also get a hit on your example '3'.
So if you have a query like this:
SELECT * FROM table WHERE
column LIKE '%how%'
AND column LIKE '%can%'
AND column LIKE '%i%'
AND column LIKE '%do%'
AND column LIKE '%this%'
Then you also get number 3. So you need to check if there are no other words. You can do this by checking the word count (if you have 5 words and all of your words are in there, you are done.).
Checking wordcount is not trivial, but there is a trick. From several sources*:
SELECT LENGTH(total_words) - LENGTH(REPLACE(total_words, ' ', ''))+1
FROM tbl_test;
should do the trick. So check the LIKE's, and check the wordcount, and you're done. But I'm not really sure this is a pretty sollution :)
http://www.webtechquery.com/index.php/2010/03/count-number-of-words-in-mysql-mysql-words-count/
and http://www.mwasif.com/2008/12/count-number-of-words-in-a-mysql-column/
(random google hits :) )
you can ask if the string where you are searching in, contains: "how" and "can" and "I" and "do" and "this"
something like this:(I don't know the syntax in mysql but see the concept)
if(string.contain("how")&&
string.contain("can")&&
string.contain("I")&&
string.contain("do")&&
string.contain("this"))
{
//you find the string
}
If you are using mysql then try this..
select * from tablename where columnname Like '%how%' AND columnname LIKE '%can%' AND columnname LIKE '%I'% AND columnname LIKE '%DO'% AND columnname LIKE '%This'%;
Here if u have dynamic value in $string then first convert it into an array spliting by space.then create a $condition varriable from the array and append that in select * from tablename where and run that query.
thanks
should be the wildcard call in mysql
select * From tablename Where columnname LIKE '%how%'
you can use regex first crate a function like this
public function part($str){
$str = str_replace('',' ',$str);
$arr = explode(' ',$str);
$rejex = '';
foreach($arr as $item){
$rejex .= "(?=.*$item)";
}
return $rejex;
}
and then use sql regex
$sql = "SELECT * FROM `table` WHERE `column` REGEXP ".part($str);
I have some columns in my table, descriptions column contains some information like;
a1b01,Value 1,2,1,60|a1b01,Value2,1,1,50|b203c,Value 1,0,2,20
with a SQL command, i need to update it.
In there, I'll use a PHP function for updating, if first and second parameters exist in current records (in description column) together.
Eg: if user wants to change the value of description that includes a1b01,Value 1 I'll execute a SQL command like that;
function do_action ($code,$value,$new1,$new2,$newresult) {
UPDATE the_table SET descriptions = REPLACE(descriptions, $code.','.$value.'*', $code.','.$value.','.$new1.','.$new2.','.$newresult)";
}
(star) indicates that, these part is unknown (This is why i need a regex)
My question is : how can i get
a1b01,Value 1,2,1,60|
part from below string
a1b01,Value 1,2,1,60|a1b01,Value2,1,1,50|b203c,Value 1,0,2,20
via regex, but a1b01 and Value 1 should be get as parameter.
I just want that; when I call do_action like that;
do_action ("a1b01","Value 1",2,3,25);
record will be : a1b01,Value 1,2,3,25|a1b01,Value2,1,1,50|b203c,Value 1,0,2,20(first part is updated...)
You don't necessarily need to use a regular expression to do this, you could use the explode function since it is all delimited
So you could do as follows:
$descriptionArray = explode('|', $descriptions); //creates array of the a1b01,Value 1,2,1,60 block
//then for each description explode on ,
for($i = 0; i < count($descriptionArray); $i++){
$parameters = explode(',', $descriptionArray[$i]);
do_action ($parameters[0],$parameters[1],$parameters[2],$parameters[3],$parameters[4]);
}
I have Sphinx Search installed as my search engine and I'm trying to add a few extra features to the search using setFilter() and SetSelect() which should allow me to do WHERE/AND clauses. But whenever I try a search, it returns no results instead of results.
Here is my sphinx.conf: http://pastebin.com/M6Kd71u0
And here's the PHP code:
require("sphinxapi.php");
$host = "localhost";
$port = 9312;
$index = "llgenre";
$select1 = "cartoon";
$label6 = "children";
$type = 4;
$limit = 20;
$ranker = SPH_RANK_PROXIMITY_BM25;
$mode = SPH_MATCH_ALL;
$sphinx = new SphinxClient();
$sphinx->setServer($host, $port);
$sphinx->setConnectTimeout(0);
$sphinx->setMatchMode($mode);
$sphinx->setRankingMode($ranker);
$sphinx->setSelect('*, select1="'.$select1.'" AND label6="'.$label6.'" AS mycond');
$sphinx->setFilter('mycond', array(1));
$res = $sphinx->query($type, $index);
die(var_dump($res));
How can I search by type = 4, filter by select1 with cartoon and finally on label6 with children?
I believe what you're attempting to do is to filter strings as attributes. Referring to the Sphinx FAQ, they outline the procedure
How do I filter, sort, or group by
string column without string
attributes?
You can do all of this, except for
precise arbtrary-length sorting over
several indexes.
To filter and group, you can replace
the string with an unique numeric ID.
Sometimes its possible to create a
lookup dictionary in the database (eg.
for fixed lists of cities or
countries), or even use an existing
one, replace strings with their IDs in
that dictionary, then filter and group
on that ID. If not, you can always
replace the string with its checksum,
eg. CRC32() or (any) 64 bits taken
from MD5() at indexing time (no need
to alter the tables!), store it using
sql_attr_uint or sql_attr_bigint
respectively, and then filter or group
on that checksum attribute. (Note that
there's a certain chance of CRC32()
collisions if you have millions of
strings but practically zero chance of
MD5() collisions.)
So, in my sphinx.conf, I might have the following...
sql_query = SELECT CRC32(string_field) AS `string_field` FROM `table`
sql_attr_uint = string_field
Then in PHP, I would apply a filter on the field like so...
$sphinx->SetFilter('string_field', array(crc32( 'filter_string' ));
--
Unfortunately, PHP has an annoying problem(bug?) when converting to crc32... something involving unsigned integers or something..
I use the following function to convert correctly
class Encode {
public static function crc32($val){
$checksum = crc32($val);
if($checksum < 0) $checksum += 4294967296;
return $checksum;
}
}
--
Be careful of character case! You may choose to convert the column to lower case while indexing eg.
sql_query = SELECT CRC32(LOWER(string_field)) AS `string_field` FROM `table`
and searching...
$sphinx->SetFilter('string_field', array(crc32(strtolower( 'Filter_String' )));