multiple where statements combined with OR in Activerecord and Ruby - ruby

I would like to do a query with activerecord (not rails) with multiple keywords that are contained in a field (so I have to use LIKE) but I don't know in advance how many keywords there will be.
My query looks like this, Word is my model.
query = ['word1','word2'] #could be more
puts "searching for #{query}"
qwords = Word.none
query.each do |qword|
puts qwords.where("word like ?", "%#{qword}%").to_sql
qwords = qwords.where("word like ?", "%#{qword}%")
end
Which gives nothing because the queries are added as AND but I need OR.
searching for ["word1", "word2"]
SELECT "words".* FROM "words" WHERE (word like '%word1%')
SELECT "words".* FROM "words" WHERE (word like '%word1%') AND (word like '%word2%')
#<ActiveRecord::Relation []>
I can't use Word.where(word: query) which uses the sql IN keyword because that only works for exact matches.
Is there a solution that doesn't involves concatenating the whole SQL that is needed ?

query = "word1 word2" #could be more
puts "searching for #{query}"
query_length = query.split.length #calculates number of words in query
Now you can put together the number of SQL queries you need regardless of the number of keywords in your query
Word.where([(['word LIKE ?'] * query_length).join(' OR ')] + (query.split.map {|query| "%#{query}%"}))
This should return
["word LIKE ? OR word LIKE ?", "%word1%", "%word2%"]
for your SQL search

Had forgotten about this question and found a solution myself afterward.
I now do the following. The problem was caused by using the resultset to do my next query on while like this it is on the whole recordset and the results are added.
#qwords = Word.none
$query.each do |qword|
#qwords += Word.where(word: qword)
end

Related

How to properly perform like queries with Quickbase

I am working with quicktable queries and everything seems to be fine.
Now I want to perform queries using like operators. For instance in PHP I can do something like:
$data ='content to search';
$stmt = $db->prepare('SELECT * FROM members where name like :name OR email like :email limit 20');
$stmt->execute(array(
':name' => '%'.$data.'%',
':email' => '%'.$data.'%',
));
Now in quick table, I have tried using CT, EX or HAS parameter etc with OR Operators. Only CT gives nearby result but not exact as per code below.
//Email = 7
//name =8
{
"from": "tableId",
"where": "{7.CT.'nancy#gmail.com'}OR{8.CT.'nancy'}"
}
Is there any way I can obtain a better search with like operators with Quickbase. The documentation here does not cover that.
CT is the closest string comparison operator in Quick Base to LIKE in SQL, but since you can't use wildcards in Quick Base queries you might need to group multiple query strings to achieve the same result. The is also a SW operator that can sometimes come in helpful for comparing parts of a strings.

LINQ query to find items where multiple substrings are searched on one column

Select * from web_data where Title like "%Lawn%" || Title like "%silk%"......and so on.
Lawn, Silk etc are in List<web_data>. So i'm looking for a way to search those substrings in the Title column(discription property). One of them must be contained, then the row should be returned.
I've tried this
query = query
.Where(x => filter.FabricType.Any(f => x.discription.Contains(x.discription)))
.AsQueryable();
It's not working. That linq to sql code returns an error:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
any alternatives?
You can use Contains() or You can also use .StartsWith() or .EndsWith().
collListItem.Where(x => x.discription.Contains("Lawn") || x.discription.Contains("silk")).ToList();

Ecto where like query acts like where ==

I'm trying to get an ecto like query working like this:
def find(searchterm) do
query = from c in Contact,
#where: fragment("? % ?", c.company_name, ^searchterm),
where: like(c.company_name, ^searchterm),
contacts = Repo.all(query)
{:ok, contacts}
end
In my table, I have a company_name "Asymptote". Using where: like/2 my query looks like this:
SELECT c0."id", c0."company_id", c0."company_name" FROM "contacts" AS c0 WHERE (c0."company_name" LIKE $1) ["Asym"] (1.0ms)
when the pg_trm search uncommented, it looks like this:
SELECT c0."id", c0."company_id", c0."company_name" FROM "contacts" AS c0 WHERE (c0."company_name" % $1) ["Asym"] (1.0ms)
As far as I can see, the queries look good, but there are no results. Since I added the index after adding "Asymptote" to the database, I expect that is why it isn't found in the pg_trm index, but why won't like/2 or ilike/2 work? When entering in the full name "Asymptote", I am able to find the record.
I faced some similar problem. Unfortunately I had no pg_trgm available. I used the LIKE as in:
from candidate in query,
where: like(candidate.first_name, ^("%#{text}%"))
This matched the text in any place of the candidate.first_name.
With the help of Mitchell Henke of Rokkincat, here's a way to get pg_trgm working with custom match percentages:
def find(searchterm) do
limit = 0.1
query = from c in Contact,
where: fragment("similarity(?, ?) > ?", c.company_name, ^searchterm, ^limit),
#where: like(c.company_name, ^searchterm),
contacts = Repo.all(query)
{:ok, contacts}
end
But I still can't get like/2 working. Also, I don't see where in Ecto source this function exists.

Ruby DBI - How to check if a recordset is empty

Using Ruby DBI, how can I check if a record set is empty? (without iterating through it or doing a count query)
sth = dbh.prepare("select * from things WHERE created_at > '#{start}'")
sth.execute
You could always just ask the result object:
res = sth.execute
res.num_rows
The operation will have to pull down all matching records, though, so if you only need a count, you might want to select that directly.
Also escape your SQL. You cannot just put arbitrary strings in there. This is better:
sth = dbh.prepare("select * from things WHERE created_at > '%s'" % sth.escape_string(start))

NHibernate advanced search headache

I really believe this is a simple problem, but one of those with a solution that's not obvious to an NHibernate newbie like me...
Here's the deal, I'm conducting my NHibernate-related queries from a data service layer that knows nothing about NHibernate (for separation of concerns). As such, I'm constructing my queries by using LINQ (Sytem.Linq).
I want to search on more than one word. For instance, if someone types in "training excel", then I will search a number of entities and related location entities based on both words.
Here's what my code looks like in my service layer right now:
// We are delimiting by spaces and commas.
string delimiterString = " ,";
char[] delimiter = delimiterString.ToCharArray();
IEnumerable<string> words = searchWords.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
// Loop through each search word in the collection and apply the "Where" clause to our IQueryable collection:
foreach (string word in words) {
matches = matches.Where(i => i.Subject.Contains(word)
|| i.Background.Contains(word)
|| i.Summary.Contains(word)
|| i.Organization.Contains(word)
|| i.Locations.Any(l => l.Organization.Contains(word))
|| i.Locations.Any(l => l.City.Contains(word))
);
}
Here's the issue... through viewing my application logs and running NHibernate Profiler, I see that the T-SQL query is correctly being constructed. The search works fine with just one search word passed in. However, if 2 or more words are detected, the last word detected is the only one searched on. For instance, if the search term was "training excel", then, as I step through my code above, both words are correctly added in the loop, but the final T-SQL output has "excel" in both logical where groups in the WHERE clause (i.e. WHERE course.Subject like ('%' + 'excel' + '%')...... AND course.Subject like ('%' + 'excel' + '%')......). There should have been "training" in the first group and "excel" in the second group.
It seems like NHibernate is using some sort of query caching for efficiency because the query signature is the same (since we're looping through all the words). Again, I have verified that both words are being used when stepping through my code.
Any ideas??
This must be the common pitfall "access to modified closure". Try
foreach (string word in words)
{
var wordLoopVariable = word;
matches = matches.Where(i => i.Subject.Contains(wordLoopVariable)
|| i.Background.Contains(wordLoopVariable)
|| i.Summary.Contains(wordLoopVariable)
|| i.Organization.Contains(wordLoopVariable)
|| i.Locations.Any(l => l.Organization.Contains(wordLoopVariable))
|| i.Locations.Any(l => l.City.Contains(wordLoopVariable))
);
And do some googling on closures.

Resources