BOOLEAN and LIKE search together with Yii2? - yii2

I use YII2 Framework and I've built this search in BOOLEAN MODE:
if( $campi[$i] == "PossessoreElenco" ){
if(strpos($valor[$i], ' OR ') !== false) {
$titOR = str_replace(" OR ", ' ', $valor[$i]);
$query.= 'MATCH(PossessoreElenco) AGAINST("'.$titOR.'" IN BOOLEAN MODE)'; }
Now, if I write "Marc*" the result show both this : "Marco", "San Marco". This is right, but is not the result that I want. I would to take only the result that STARTS with the word that I write. So, at the end if I write Marc* OR Mich* in BOOLEAN MODE, I want to search for the result that STARTS with "Marc" or "Mich" (example 'Marco' or 'Michele') and not all results that CONTAINS the words (example, I don't want 'San Marco'). There is an opportunity to implement this option mantaining the boolean search?
I can use LIKE 'Marc%', but in this solution I lose the boolean search.
Thank you for the help!

The Boolean Full-Text Searches is based on word and don't care for the beginning of the string ..
if you need this you could enforce the query adding an having cluase fro filter the risulting rows
WHERE MATCH(PossessoreElenco) AGAINST( ? IN BOOLEAN MODE)
HAVING PossessoreElenco LIKE caoncat(?,'%')
NB The use of an having clause for filter the result without aggregation function is pretty improper
So you could use your main query as a subquery for apply the like eforcemnet
select *
from (
SELECT
....
WHERE MATCH(PossessoreElenco) AGAINST( :my_word IN BOOLEAN MODE)
) T
WHERE T.PossessoreElenco LIKE concat(:my_word,'%')
You should avoid the use of php var in sql because this can produce sqlijcetion for avoid tgis you could use named param and use the related binding function provided by Yii2

Related

Creating GORM dynamic query with optional paramters

I've been stuck on a GORM issue for about a full day now. I need to be able to filter a messages table on any of 4 things: sender, recipient, keyword, and date range. It also has to paginate. Filtering by sender and recipient is working, and so is pagination. So far this is the query that I have come up with, but it does not seem to work for date ranges or keywords.
Here is how I am selecting from MySQL
db.Preload("Thread").Where(query).Scopes(Paginate(r)).Find(&threadMessages)
I am creating the query like this:
var query map[string]interface{}
Then based on which parameters I am passed, I update the query like this by adding new key values to the map:
query = map[string]interface{}{"user_id": sender, "recipient_id": recipient}
For dates it does not seem to work if I try something like this:
query = map[string]interface{}{"created_at > ?": fromDate}
And for a LIKE condition is also does not seem to work:
query = map[string]interface{}{"contents LIKE ?": keyword}
The reason I chose this approach is that I could not seem to get optional inputs to work in .Where since it takes a string with positional parameters and null positional parameters seem to cause MySQL to return an empty array. Has anyone else dealt with a complicated GORM issue like this? Any help is appreciated at this point.
Passing the map[string]interface{} into Where() only appears to work for Equals operations, or IN operations (if a slice is provided as the value instead).
One way to achieve what you want, is to construct a slice of clause.Expression, and append clauses to the slice when you need to. Then, you can simply pass in all of the clauses (using the ... operator to pass in the whole slice) into db.Clauses().
clauses := make([]clause.Expression, 0)
if mustFilterCreatedAt {
clauses = append(clauses, clause.Gt{Column: "created_at", fromDate})
}
if mustFilterContents {
clauses = append(clauses, clause.Like{Column: "contents", Value: keyword})
}
db.Preload("Thread").Clauses(clauses...).Scopes(Paginate(r)).Find(&threadMessages)
Note: If you're trying to search for content that contains keyword, then you should concatenate the wildcard % onto the ends of keyword, otherwise LIKE behaves essentially the same as =:
clause.Like{Column: "contents", Value: "%" + keyword + "%"}
My final solution to this was to create dynamic Where clauses based on which query params were sent from the client like this:
fields := []string{""}
values := []interface{}{}
If, for example, there is a keyword param:
fields = []string{"thread_messages.contents LIKE ?"}
values = []interface{}{"%" + keyword + "%"}
And to use the dynamic clauses in the below query:
db.Preload("Thread", "agency_id = ?", agencyID).Preload("Thread.ThreadUsers", "agency_id = ?", agencyID).Joins("JOIN threads on thread_messages.thread_id = threads.id").Where("threads.agency_id = ?", agencyID).Where(strings.Join(fields, " AND "), values...).Scopes(PaginateMessages(r)).Find(&threadMessages)

filter string only contains q in mysql

I need help in mysql query, i written this query
select * from post where content REGEXP '^q'
this query is working but it also includes spaces in filter, what i want to do if any content string like "qqqqqq" or "qqqq" or "qqq" or "qq" or "q" for this string only it should have to filter, right now what is happening if i have string like "qqqq qq" then also it is giving me the result, it should not consider that space, can anyone please help me to resolve this issue ?
You can fix your regexp like next:
select * from post where content REGEXP '^q+$';
This regular expression mean the string starts with q and contain only 1 or more q symbols till end of string
Test it on SQLize.online
Try Using this ^q+(?![\s])+$ Regular Expression.
Above RegExp will check for string starting with q and without space.
You don't really need a regex for this. String functions are likely to be more efficient. You can replace all "q"s with empty strings, and ensure that that resulting string is empty:
select * from post where replace(content, 'q', '') = ''
Note that this also allows the empty string. If you want to avoid that, then:
select * from post where content <> '' and replace(content, 'q', '') = ''

What is the use of 'WHERE TRUE' in MySQL

I'm working on my colleague's old project and I found on her code WHERE TRUE AND ID='1' AND STAT='1'.
I've tried to removed TRUE AND so the query become WHERE ID='1' AND STAT='1' and get the same result.
I know we can use TRUEas boolean to search 'where something is true' such as WHERE FLAG = TRUE and this MySQL documentation state that
The constants TRUE and FALSE evaluate to 1 and 0, respectively. The constant names can be written in any lettercase.
I also tried SELECT * FROM MYTABLE WHERE TRUE but it's just the same as SELECT * FROM MYTABLE
what is the purpose of TRUE in her query?
It has no specific functional purpose. Your colleague may have included it if they were adhering to a specific style guide that recommends that all SELECT queries have explicit WHERE clauses. If an explicit WHERE clause is not provided, the default is to select all rows. Adding a WHERE clause that is always true will have the same effect.
Another way this query could have come about is if it was generated by a code generation tool that always had to write in a WHERE clause due to the way it was written.
for example:
myQuery = "SELECT X FROM Y WHERE " + ConditionMet(data)?" AccountID = '" + AcctId + "'" : "1=1";
This means that if ConditionMet(data) is true, then only return rows where AccountID matches the AcctId you are passing in. If it is false, then return all rows.
Adding a "dummy" 1=1 makes the code generator simpler to write. More generally, 1=1 is as legitimate a boolean clause as any other, and can be "dropped" into a conditional expression without having to special-case the query to omit the WHERE clause.
Similarly, adding a WHERE clause that is always false (e.g. "WHERE 1=0") will result in zero rows being returned.
Do note that the example code here is vulnerable to SQL Injection, so it should not be used in cases where you are dealing with AccountID's that you did not produce yourself. There are multiple ways to secure it that are beyond the scope of this answer.
If you're writing your SQLString on runtime, and you might add different "where" clausules but you don't know which of all of them will be the first, it makes it easy as all of them may start with "AND ....."
Example:
SQLString:='SELECT * FROM YOUTABLE WHERE TRUE'
If condition1 THEN SQLString:=SQLString+' AND Whatever=whatever';
If condition2 THEN SQLString:=SQLString+' AND Whatever=whatever';
If condition3 THEN SQLString:=SQLString+' AND Whatever=whatever';
If condition4 THEN SQLString:=SQLString+' AND Whatever=whatever';
otherwhise, you should add the WHERE clause not on the first SQLString:= but on the first condition that happens to be true, which you don't know will it be a priori
it is not as much relevant but if find important where adding dynamic conditions,for example in php.
$condition_stmt="";
if ($start_date !="" && $end_date!="")
{
$condition_stmt="and nos.status_date between '".$start_date."' and '".$end_date."'";
}
else if ($start_date!="")
{
$condition_stmt="and nos.status_date >='".$start_date."'";
}
else
{
$condition_stmt="and nos.status_date <='".$end_date."'";
}
$sql="select * from table where true ".$condition_stmt=.";

SSRS expression to check if a string is present in a string array

I am applying a filter to a Series Group in Report.
I want to filter out data by country name.
For ex. I would like to filter out Nepal, Japan & China.
Right now my filter expression is to add 3 filters, one for each country. Is there a better way to do it, may be in a single filter?
Ideally I am imagining it to be like
[CountryName] Not In ["Japan","China","Nepal"]
Use a bit of custom code to detect the country instead, and filter on that.
Public Function IsProhibitedCountry(ByVal name As String) As Boolean
Select Case name.ToLower()
Case "japan","china","nepal"
Return False
Case Else
Return True
End Select
End Function
The filter:
[=Code.IsProhibitedCountry(Fields!CountryName.Value)] [=] [=True]

In LINQ to SQL, how do you determine what column elements is a sub-set of another column (i.e. Like-Sql statement)

Here is some code:
//all possible search terms of interest
searchTerms = from s in dc.SearchTerms
select s.term;
//all possible results
var results = from r in dc.Data
select r.hyperlinks;
I want to perform an operation where I get all "r.hyperlinks" that contains s.term.
It is something like r.hyperlinks.Contains(s.term). How can I do this?
It's almost as you wrote it in english:
var results = from r in dc.Data
where searchTerms.Any(x => r.hyperlinks.Contains(x))
select r.hyperlinks;
That's all!
You can put any condition you might come up inside a where clause. Actually, you can put whatever returns a boolean.
Local sequences cannot be used in many LinqToSql operators. But your original question didn't require a local sequence.
var results =
from r in dc.Data
where dc.SearchTerms.Any(s => r.hyperlinks.Contains(s.Term))
select r.hyperlinks;