Keyword based search in asp.net mvc application - c#

I was doing a keyword based search in an asp.net mvc application from a sql database.
The database has a table Resources which has entries of the following format:
resource
english pdf
maths elementary book
english vocabulary
The user is then asked to enter a query which generates the resource which matches the query:
e.g. The user enters "Get all english books"
query = "Get all english books";
I first tokenise the query string and push the contents into an array:
string[] keywords = query.Split(' ');
I do a keyword based match with all the keywords with all the entries in the table. If any of the keywords are present in any of the resources I return that row.
Since I don't know what would be the number of keywords prior, I have to write a dynamic query string. Here is the code that I have written:
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
// Tokenize the query
String[] tokens = searchQuery.Split(' ');
if (tokens.Length != 0) {
string query = "SELECT * FROM Queries WHERE query LIKE '(%'" + "#0" + "'%)'";
for (int i = 1; i < tokens.Length; i++)
query += " OR query LIKE '(%'" + "#" + i + "'%)'";
query += ";";
Console.WriteLine("The query is : " + query);
Console.ReadLine();
SqlCommand sqlCommand = new SqlCommand(query, sqlConnection);
sqlCommand.CommandType = System.Data.CommandType.Text;
for (int i = 0; i < tokens.Length; i++)
sqlCommand.Parameters.AddWithValue("#"+i, tokens[i]);
using (SqlDataReader reader = sqlCommand.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("{0}", reader[1]);
}
}
}
This does not generate the expected output. Can somebody has experience with this.

Related

C# Retrieve ALL SQL Query Results

else if (listBox1.SelectedIndex == 1)
{
String sql2 = "SELECT FirstName, LastName FROM Players WHERE Team = 'Milwaukee Bucks'" +
"AND Number < 24";
// command statement
command = new SqlCommand(sql2, cnn);
SqlDataReader reader = command.ExecuteReader();
// Get table values
if (reader.Read())
{
textBox1.Text = reader.GetString(0).ToString() + " " + reader.GetString(1).ToString();
}
cnn.Close();
command.Dispose();
}
Above is a section of my code. I have a list box with options for the user to choose, and based on which item is selected, a display button will run a query and return the results to a textbox.
However, when I run the code I am only getting one result back. The query returns players on the Bucks who have a number less than 24. There should be multiple of them but I am only getting one in my C# application.
You need to use a while loop to read all the lines instead of reading a single line (via Read()).
Microsoft Documentation has an example of how to use the while loop.
StringBuilder sb = new StringBuilder()
while (reader.Read())
{
sb.AppendLine(reader.GetString(0).ToString() + " " + reader.GetString(1).ToString());
}
textBox1.Text = sb.ToString();

Convert textbox to multi-valued, parameterized SQL query

I'm a newbie when it comes to C#, but have some experience with C, Python and MATLAB. I wrote a simple C# program that takes in some user input and converts it into a (parameterized) SQL query. I've successfully converted the datetimepicker into a SQL query; however, I have another parameter (serial numbers) that the user would input into a textbox. They can enter multiple serial numbers, separated by commas. Once the user clicks on 'Submit', the SQL query is sent and the results displayed in a dataGridView.
It works with a single value (i.e. a single serial number), but when I try to put in multiple values, it doesn't work.
I've tried some suggestions like separating the textbox string into an array of values.
private DataTable GetResults()
{
DataTable dtResults = new DataTable();
string connString = ConfigurationManager.ConnectionStrings["dbx"].ConnectionString;
using (SqlConnection con = new SqlConnection(connString))
{
using (SqlCommand cmd = con.CreateCommand())
{
string[] numbers = textBox2.Text.Split(',');
var parameters = new string[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
parameters[i] = string.Format("#SN{0}", i);
cmd.Parameters.AddWithValue(parameters[i], numbers[i]);
}
cmd.CommandText = string.Format("SELECT [TestDate],[ParamName],[SerialNumber],[TestDataID],[MeasuredValue]," +
"[MaximumLimit],[MinimumLimit],[PassResult] FROM [dbo].[Device.ParametricTestResults] " +
"WHERE SerialNumber IN ({0}) " +
"AND (TestDate BETWEEN (#start) AND (#end)) " +
"AND PassResult = 1", string.Join(", ", parameters));
cmd.Parameters.AddWithValue("#start", dateTimePicker1.Text);
cmd.Parameters.AddWithValue("#end", dateTimePicker2.Text);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
dtResults.Load(reader);
}
}
return dtResults;
}
And the 'Submit' button has the following code attached to it:
private void button12_Click(object sender, EventArgs e)
{
TestResultsdataGridView.DataSource = GetResults();
}
Again, the datagridview should display entries for multiple serial numbers, but it only works for one.

Passing multiple values to single parameter in SQL inline query using C#

I am new to coding and looking for some help on how to pass multiple values to a single parameter in an inline SQL query. I have framed the below query, but I heard this could result in SQL-injection issue. Kindly help on how can I frame the below by using parameter based in the SQL query.
string query = "Select ID, email FROM DBTABLE WHERE email in (";
var stringBuiler = new StringBuilder();
using (StringReader stringReader = new StringReader(DownloadIDtextBox.Text))
{
string line;
string prefix = "";
while ((line = stringReader.ReadLine()) != null)
{
stringBuiler.Append(prefix);
prefix = ",";
stringBuiler.Append("'" + line + "'");
}
}
query += stringBuiler.ToString() + ")";
SqlDataAdapter da = new SqlDataAdapter(query, Connection);
DataTable dt = new DataTable();
da.Fill(dt);
Just want to mention that ID is GUID format.
If you are doing it manually, the process would be (basically):
var stringBuiler = new StringBuilder("Select ID, email FROM DBTABLE WHERE email in (");
// create "cmd" as a DB-provider-specific DbCommand instance, with "using"
using (...your reader...)
{
int idx = 0;
...
while ((line = stringReader.ReadLine()) != null)
{
// ...
Guid val = Guid.Parse(line);
// ...
var p = cmd.CreateParameter();
p.Name = "#p" + idx;
p.Value = val;
if (idx != 0) stringBuiler.Append(",");
stringBuiler.Append(p.Name);
cmd.Parameters.Add(cmd);
idx++;
}
}
cmd.CommandText = stringBuiler.Append(")").ToString();
and use that... meaning: you don't use inline SQL - you use fully parameterized SQL. There are tools in the ORM/micro-ORM families that will help immensely here, though - making it a one-liner.

CSV - Import file to a Sql database through code

I need to load data from text file/csv file to a SQL Server database. I used the code shown below to load data and is loading to the database the problem is the data in second column may contain space but I use space for separate the column data.
i.e.
200007 XXXX Check XXXX yyy 50
200013 YYYY Check ZZZZ yyy 50
200022 nnnn 25Mg 30 Tabs
200042 mmmm 30 Mg 30 Tabs
I need to store the first ID number in the first column and the remaining text in second column:
string str = Properties.Settings.Default.con;
SqlConnection con = new SqlConnection(str);
SqlCommand cmd = new SqlCommand();
try
{
cmd.Connection = con;
con.Open();
cmd.CommandText = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='TEMP_AUTO' AND xtype='U')" +
"CREATE TABLE TEMP_AUTO (" +
"ID varChar(10) NULL," +
"NAME varChar(50) NULL," +
"DATE TIMESTAMP NULL," +
")";
cmd.ExecuteNonQuery();
string query1 = "INSERT INTO [dbo].[TEMP_AUTO]([ID],[NAME]) VALUES (#num1, #num2)";
cmd.CommandText = query1;
string[] allLines = File.ReadAllLines(txtFilePath.Text);
for (int i = 0; i < allLines.Length; i++)
{
cmd.Parameters.Clear();
string[] items = allLines[i].Split(new char[] { ' ' });
cmd.Parameters.AddWithValue("#num1", items[0]);
cmd.Parameters.AddWithValue("#num2", items[1]);
cmd.ExecuteNonQuery();
}
MessageBox.Show("Successfully saved your data");
}
finally
{
cmd.Dispose();
con.Close();
}
A possible solution might be this:
string[] allLines = {
"200007 XXXX Check XXXX yyy 50",
"200013 YYYY Check ZZZZ yyy 50",
"200015 ",
"2541111"
};
for (int i = 0; i < allLines.Length; i++)
{
string param1 = null;
string param2 = null;
int spaceIndex = allLines[i].IndexOf(' ');
if (spaceIndex > 0)
{
param1 = allLines[i].Substring(0, spaceIndex);
if (spaceIndex < allLines[i].Length - 1)
{
param2 = allLines[i].Substring(spaceIndex + 1, allLines[i].Length-1 - spaceIndex);
}
}
else
{
param1 = allLines[i];
}
Console.WriteLine("param1:{0} param2:{1}", param1, param2);
}
Use SSIS to map this file as long as it has a standard structure to SQL Table.
Is this a one time thing? Have you tried getting the data organized in Excel then using the SSMS import tool to bring it in? If you right click on the Database then Tasks > Import Data the wizard will appear when given the option to choose the source, choose Excel. Flat files is an option but if you can format it in Excel first that tends to work better.
As you click through you can adjust the column types and where the breaks are, much like importing into Excel itself.
Use the String.Split(Char[], Int32) method to split on the first occurrence of ' ' only. Eg
string[] items = allLines[i].Split(new char[] { ' ' }, 2);
Refs: MSDN and previous relevant question
Use the below code.
using (StreamReader sr = File.OpenText("txtFile.txt")) // Mention the path,if the file is not in application folder.
{
string str = String.Empty;<br/>
while ((str = sr.ReadLine()) != null)
{
string[] item = str.Split(' ');
SqlConnection con = new SqlConnection(str);
SqlCommand cmd = new SqlCommand();
string query1 = "INSERT INTO [dbo].[TEMP_AUTO]([ID],[NAME]) VALUES ('" + item[0] + "', '" + item[1] + "')";
// Do remain part<br/>
}
}

SQLite code optimization

I am a hobbyist programmer and writing a reporting tool to export values from an SQLite database to Excel.
The Excel part is written and working, the data I am retrieving from SQLite is creating a block in the program and taking several minutes to process.
I have rewritten the code out using generic values to help illustrate the processes. The initial populateList module is taking a negligible amount of time, but I have included it below as that is the providing the data for the doStuff module. The populateList currently retrieves approximately 500 distinct records.
I need the program to iterate through all the values retrieved by the populateList and do several counts. It is then populating another list valuesCount with the counted values.
I tried to improve the speed by looping through the list without closing the SQLite connection, but the improvement wasn't enough. Is there a more efficient way to retrieve this information from the databse?
public list<string>populateList()
{
List<string>values = new list<string>();
using (SQLiteConnection con = new SQLiteConnection(Passer.connstr))
{
con.Open();
string distinctValues = "SELECT DISTINCT \"value list\" FROM valueTable order by \"value list\" ";
using (SQLiteCommand cmd = new SQLiteCommand(distinctValues, con))
{
SQLiteDataReader sqReader;
sqReader = cmd.ExecuteReader();
while (sqReader.Read())
{
values.Add(sqReader["value list"].ToString());
}
}
}
return values;
}
public void doStuff()
{
bool blanks = false;
string singleValue = string.Empty
string query = string.Empty;
List<string> getInitialValues = populateList();
list<string> valuesCount = new list<string>();
using (SQLiteConnection con = new SQLiteConnection(Passer.connstr))
{
con.Open();
for(int i = 0; i < getInitialValues.Count; i++)
{
blanks = false;
singleValue = getInitialValues[i];
if(singlevalue == "")
{
singleValue = \"\";
blanks = true;
}
for (int x = 0; x < 6; x++)
{
string statement = string.Empty;
switch(x)
{
case 0:
statement = "SELECT COUNT(*) from valueTable where \"column1\" = ";
break;
case 1:
statement = "SELECT COUNT(*) from valueTable where \"column2\" = \"condition 1\" and \"column1\" = ";
break;
case 2:
statement = "SELECT COUNT(*) from valueTable where \"column3\" = \"condition 3\" and \"column1\" = ";
break;
case 3:
statement = "SELECT COUNT(*) from valueTable where \"column4\" = \"condition 4\" and \"column1\" = ";
break;
case 4:
statement = "SELECT COUNT(*) from valueTable where \"column5\" = \"condition 5\" and \"column1\" = ";
break;
case 5:
statement = "SELECT COUNT(*) from valueTable where \"column6\" = \"condition 6\" and \"column1\" = ";
break;
}
if (blanks == true)
{
query = System.String.Format("{0}{1}", statement, singleValue);
}
else
{
query = System.string.format("{0}\"{1}\"", statement, singleValue);
}
using (SQLiteCommand cmd = new SQLiteCommand(query, con))
{
string countValues = cmd.ExecuteScalar().ToString();
valuesCount.Add(countValues);
}
}
}
}
}
Consider writing it as a single SQL query.
You are performing many queries when it very much looks like you simply need to perform a 'conditional count' on the columns. The SQL would be along the lines of
select
val,
col1 = sum(case when col1 = 'cond1' then 1 end)
from valtbl
group by val
you wouldn't even need the first method to get the list of distinct values.
Alternatively as the table seems reasonably small select what you need into a list of 'rows' and use Linq to Objects to do the counts.
You are querying the database multiple times to get the same information.
I would suggest not to do any db calls on dostuff method, rather use a single query for fetch the records form valuetable.
then you can do the count operations on the list itself.
For example get
"SELECT 'valueCol' , 'col1', 'col2' from valueTable"
would be your only query and you would store it in a list(say valueList).
Then on C# side you can use
//not actual code just a sample idea
var distinctValues = valueList.select(v => w.valueCol).Distinct()
var count = 0;
switch(case):
case 0:
count += valueList.where(v => v.col1 == condition).Count();
break; //and so on...

Categories