I'm creating a search algorithm based on keywords and sometimes phrases. I want to output results based on each word of every phrase in the search bar.
Below is my code which works fine:
var searchWords = Request["searchTerm"].Split(' ');
IEnumerable<dynamic> stories = Enumerable.Empty<string>();
var sqlSelect = "SELECT TOP 10 Feeds.* FROM Feeds WHERE Feeds.AdminPublish=#1 AND Title LIKE #0 ORDER BY UploadDate DESC";
foreach(var word in searchWords)
{
stories = stories.Concat(db.Query(sqlSelect, "%" + word + "%",).ToList());
}
In my View -Page (Result Page)
#foreach (var d in stories){
//Show Title and description
#d.Title
#d.Username
}
Problem
Let's say am searching for "xmas of Annoying", and after searching the db, it splits the phrase into three and returns results based on LIKENESS/SIMILARITIES of the three found words. I get aresults like
The Sociology of Annoying Xmas Songs
Welcome to the future
The Sociology of Annoying Xmas Songs
Welcome to the future
The Sociology of Annoying Xmas Songs
Welcome to the future
How do I condition my result to not show show results that have similar ID's or how do I remove excess duplicates
Yo can use Distinct Keyword To Select Distinct from Table
var sqlSelect = #"SELECT distinct TOP 10 Feeds.*
FROM Feeds WHERE Feeds.AdminPublish=#1 AND
Title LIKE #0 ORDER BY UploadDate DESC";
EDIT:
then You can do like this
foreach(var word in searchWords)
{
stories = stories.Concat(db.Query(sqlSelect, "%" + word + "%",).ToList());
}
stories= stories.Distinct<dynamic>();
Also you can use the Distinct extension method in lambda expression to achive the same in your View (Razor)
#foreach (var d in stories.Distinct()){
//Show Title and description
#d.Title
#d.Username
}
You can also provide a specific property on the basis of which the list can be made distinct, like:
stories.Distinct(x=>x.Title)
//Or
stories.Distinct(x=>x.UserName)
I would say to not add duplicate values to stories in the first place...
Something similar to this:
foreach(var word in searchWords)
{
lst = db.Query(sqlSelect, "%" + word + "%",).ToList()
foreach(var v in lst)
{
if (!stories.Contains(v))
stories.Add(v)
}
}
Mike from #Mikesdotnetting.com came up with a dynamic solution, most credit goes to him, and some to me for spotting out ways to tweek the structure, for future reference; heres the solution
var searchWords = Request["searchTerm"].Split(' ').Select(s => "%" + s + "%");
var sql = "SELECT TOP 10 Feeds.* FROM Feeds WHERE";
for(var i = 0; i < searchWords.Count(); i++)
{
sql += i == 0 ? "" : " OR ";
sql += " Title LIKE #" + i;
}
sql += " ORDER BY UploadDate DESC";
var stories = db.Query(sql, searchWords.array());
IF you want a result that might look something like this:
SearchTerm = "one two three"
SQL = ... where title like '%one%' or title like '%two%' or title like '%three%' or fname like '%one%' or fname like '%two%' or fname like '%three%' WHERE A FINAL CONDITION BINDS THEM ALL etc
If so, try this:
var fields = new List<string>{"Title", "SubTitle", "Fname", "UserName", "Link"};
var searchWords = Request["searchTerm"].Split(' ').Select(s => "%" + s + "%").ToList();
var sql = "SELECT TOP 10 Feeds.* FROM Feeds WHERE (";
System.Text.StringBuilder sb = new StringBuilder();
var i = 0;
foreach(var word in searchWords)
{
foreach(var field in fields)
{
sb.AppendFormat(" OR {0} LIKE #{1}", field, i);
}
i++;
}
sql = sql + sb.ToString().Trim().TrimStart("OR".ToCharArray()) + string.Format(") AND Feeds.AdminPublish=#{0} ORDER BY UploadDate DESC", i);
searchWords.Add(your_parameter_value_for_AdminPublish);
var stories = db.Query(sql, searchWords.ToArray());
Related
I'm wondering if its possible to make this easier.
So, I have an arraylist of strings called names and an arraylist of strings called last_name.
When I'm constructing select statement, I want to combine every entry in names with everything in last_name and search in database like:
SELECT * FROM DB WHERE (names='NAMES[0]' AND last_name='LAST_NAME[0]')
or (names='NAMES[0]' AND last_name='LAST_NAME[1]')
or (names='NAMES[1]' AND last_name='LAST_NAME[0]')
or (names='NAMES[1]' AND last_name='LAST_NAME[1]')
This is an example, In my project I have 6 Lists, and I need every combination, and the easiest way was to make for in for in for in for...
Thanks a lot
This should work by using a query like this :
SELECT *
FROM DB
WHERE Name IN (#name1,#name2,#name3) AND LastName IN (#lastName1, #lastName2, #lastName3)
You can build this query in a for-loop, like this :
var names = new[] {"John", "Peter"};
var lastnames = new[] { "Doe", "Waylander" };
var nameParams = "";
var lastNameParams = "";
var cnt = 0;
foreach (var name in names)
{
var nameString = "#name" + cnt;
if (cnt!=0)
{
nameParams += ",";
}
nameParams += nameString;
cmd.Parameters.Add(nameString, name);
cnt++;
}
cnt = 0;
foreach (var lastName in lastnames)
{
var lastNameString = "#lastName" + cnt;
if (cnt != 0)
{
lastNameParams += ",";
}
lastNameParams += lastNameString;
cmd.Parameters.Add(lastNameString, lastName);
cnt++;
}
cmd.CommandText = #"SELECT *
FROM DB
WHERE NAME IN (" + nameParams + #")
AND LastName IN (" + lastNameParams + ")";
var result = cmd.ExecuteReader();
The only limitation is the number of parameters (IIRC it is about 1000). Another good alternative would be a stored procedure, like already mentioned in the comments.
I want to use Regex to retrieve the person and its address.
The result wild be :
All Frank Anderson and its address inside of a string list.
Problem:
The problem I'm facing is that I cannot retrieve the second name that is "Frank Andre Anderson" based on my regex.
It also might be other people who can have another second name.
Thank you!
string pFirstname = "Frank"
string pLastname = "Anderson";
string input = w.DownloadString("http://www.birthday.no/sok/?f=Frank&l=Anderson");
Match theRegex8 = Regex.Match(input, #"(?<=\><b>)" + pFirstname + "(.+?)" + pLastname + "</b></a></h3><p><span>(.+?<)", RegexOptions.IgnoreCase);
foreach (var matchgroup in theRegex8.Groups)
{
var sss = matchgroup;
}
The current result that I'm using the code is:
You must be looking for something like
(?<=>[^<]*<b>)Frank([^<]+)Anderson</b></a></h3><p><span>([^<]+)
See concise RegexStorm demo
In C#, the regex declaration will be
Match theRegex8 = Regex.Match(input, #"(?<=>[^<]*<b>)" + pFirstname + "([^<]+)" + pLastname + "</b></a></h3><p><span>([^<]+)", RegexOptions.IgnoreCase);
The problem you had was with . matching any character while we need to restrict to a non-angle bracket.
Update
Perhaps, you could leverage HtmlAgilityPack by getting all <a> tags that have <b> as the first child, and then get the InnerText that meets your conditions:
var conditions = new[] { pFirstname, pLastname};
var seconds = new List<string>();
var webGet = new HtmlAgilityPack.HtmlWeb();
var doc = webGet.Load("http://www.birthday.no/sok/?f=Frank&l=Anderson");
var a_nodes = doc.DocumentNode.Descendants("a").Where(a => a.HasChildNodes && a.ChildNodes[0].Name == "b");
var res = a_nodes.Select(a => a.ChildNodes[0].InnerText).Where(b => conditions.All(condition => b.Contains(condition))).ToList();
foreach (var name in res)
{
var splts = name.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
if (splts.GetLength(0) > 2) // we have 3 elements at the least
seconds.Add(name.Trim().Substring(name.Trim().IndexOf(" ") + 1, name.Trim().LastIndexOf(" ") - name.Trim().IndexOf(" ") - 1));
}
This way, you will get just the second names. I could not test this code, but I think you get the gist.
I have this method that should take an unknown amount of id's.
I got this method almost done but it isnt secure yet for obvious reasons, i know i could write my own method to strip the parameters but i would be more comfortable by using some build in method for this.
Here is the method
public static List<LocationModel> FetchCitiesByAreas(IEnumerable<string> areas)
{
using (var db = new BoligEnt())
{
var sqlQuery = new StringBuilder();
var first = true;
sqlQuery.Append("SELECT DISTINCT a.city AS City, a.zip AS Zip ");
sqlQuery.Append("FROM zip_city AS a ");
sqlQuery.Append("WHERE country = 1 ");
foreach (var d in areas)
{
if (first)
{
sqlQuery.Append("AND a.area_id = '" + d + "'");
first = false;
}
else
{
sqlQuery.Append("OR a.area_id = '" + d + "'");
}
}
return db.Database.SqlQuery<LocationModel>(sqlQuery.ToString()).ToList();
}
}
i know it have this function built in but as i stated earlier i dont know the exact amount of ids that will come in
db.Database.SqlQuery<LocationModel>("SELECT * FROM table WHERE id = #p0 ;", id).ToList();
Thanks
While I completely agree with paqogomez, in that you should just use LINQ to do the query, the .SqlQuery has the ability to take a parameter array. You could change your statement to look like this:
var sqlQuery = new StringBuilder();
sqlQuery.Append("SELECT DISTINCT a.city AS City, a.zip AS Zip ");
sqlQuery.Append("FROM zip_city AS a ");
sqlQuery.Append("WHERE country = 1 ");
for (int i = 0; i < areas.Count; i++)
{
if (i == 0)
{
sqlQuery.Append("AND (a.area_id = #p" + i.ToString());
}
else
{
sqlQuery.Append(" OR a.area_id = #p" + i.ToString());
}
}
sqlQuery.Append(")");
var results = db.Database.SqlQuery<LocationModel>(sqlQuery.ToString(), areas.ToArray()).ToList();
I added the missing parenthesis needed to your query to correctly filter out the OR results as well. I've also taken the assumption that areas is something like a List, or at least something you can easily get the count from.
Why dont you just use Linq?
var locations = (from zip in db.zip_city
where areas.Contains(zip.area_id) && zip.Country == 1
select new LocationModel{
City = zip.City,
Zip = zip.Zip
})
.Distinct()
.ToList();
If you still want to parameterize your query, you need to use EntityCommand
Also note that your query will fail because you havent put parenthesis around your OR statements.
I suggest structuring your sql like this:
string sqlQuery =
#"SELECT DISTINCT a.city AS City, a.zip AS Zip
FROM zip_city AS a
WHERE country = 1 AND (1=0 "
for (int i = 0; i < areas.Count; i++)
{
sqlQuery.Append("OR a.area_id = #d" + i.ToString() + " ");
}
sqlQuery.Append(")");
I enter the data in 2 aspx memo like this :
aspxmemo1 = php;visual basic;c#
aspxmemo2 = visual basic;javascript
question :
how to check if any data was similar between the 2 aspxmemo that it will show an error message.
Note:
In the above examples, the same data is: "Visual Basic".
Assuming your memo's are strings: if you split the strings on ';', you have nice collections, which are far more easy to operate on for example with Linq.
var aspxmemo1 = "php;visual basic;c#";
var aspxmemo2 = "visual basic;javascript";
var collection1 = aspxmemo1.Split(';');
var collection2 = aspxmemo2.Split(';');
if (collection1.Intersect(collection2).Any())
{
//Do Something
}
//Or iterate over the duplicate memo's (you get the point)
foreach(var item in collection1.Intersect(collection2))
{
Console.WriteLine(item + " occured in both collections!");
}
Try this way.
string aspxmemo1 = "php;visual basic;c#";
string aspxmemo2 = "visual basic;javascript";
string copies ="";
string[] group1 = aspxmemo1.Split(';');
string[] group2 = aspxmemo2.Split(';');
foreach (string x in group1)
{
if (group2.Contains<string>(x))
{
copies += x + Environment.NewLine;
}
}
MessageBox.Show(copies);
I've wrriten a code which searchs the database but i don't know why when i search for some specific keywords it'll show other links which are unrelated. here's the code and the result.
Page.Title = "Catalog Search";
var db = Database.Open("Shopping");
var searchWords = Request["searchTerm"].Split(' ');
IEnumerable<dynamic> result = Enumerable.Empty<string>();
var sqlSelect = "SELECT ProductId, ProductTitle FROM Products WHERE " +
"ProductTitle LIKE #0";
foreach(var word in searchWords)
{
result = result.Concat(db.Query(sqlSelect, "%" + word + "%").ToList());
}
so i searched for "Samsung LCD" and here's the result.
Samsung - 15" Series 9 Ultrabook Laptop
Samsung - Galaxy Tab 2 7.0
Samsung - 32" Class - LCD
Samsung - 32" Class - LCD
i've seen a php code which is exactly what i want but unfortunately i don't know how to convert it. here's the php code.
$searchTerms = explode(' ', $bucketsearch);
$searchTermBits = array();
foreach ($searchTerms as $term) {
$term = trim($term);
if (!empty($term)) {
$searchTermBits[] = "bucketname LIKE '%$term%'";
}
}
...
$result = mysql_query("SELECT * FROM buckets WHERE ".implode(' AND ', $searchTermBits).");
and the result of the php search code.
SELECT * FROM buckets WHERE bucketname LIKE '%apple%' AND bucketname LIKE '%and%' AND bucketname LIKE '%pear%'
I took the liberty of adding a few null checks and such, but the code for C# would pretty much look like this:
// make sure search terms are passed in, and remove blank entries
var searchTerms = Request["searchTerms"] == null ?
new string[] {} :
Request["searchTerms"].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
// build the list of query items using parameterization
var searchTermBits = new List<string>();
for (var i=0; i<searchTerms.Length; i++) {
searchTermBits.Add("bucketname LIKE #" + i);
}
// create your sql command using a join over the array
var query = "SELECT * FROM buckets";
if (searchTerms.Length > 0) {
query += " WHERE " + string.Join(" AND ", searchTermBits);
}
// ask the database using a lambda to add the %
var db = Database.Open("StarterSite");
var results = db.Query(query, searchTerms.Select(x => "%" + x + "%").ToArray());
// enjoy!
Response.Write(results.Count());
Let me know if you run into any more trouble!