Library catalog search sql statement - c#

I want the user to select the search criteria for his books here is code, suggestions please!!
String keyword=Textbox1.Text; //User types keyword
String userCriteria=Textbox2.Text;// Can be Title, Author, Subject or ISBN;
String sql="Select * from tableBooks WHERE '"+keyword+"' like '%"+userCriteria+"'%";
How to let the user select their own criteria for searching the database?

You certainly need a better way to build your query.
You do not directly take input from the user without certain measure of checking or filtering and put it in your query. That would expose your application to sql injections.
Use SQL parameters.
Try this link as reference :http://www.dotnetperls.com/sqlparameter
example :
using (SqlCommand command = new SqlCommand("Select * from tableBooks WHERE #Field LIKE #Value", connection))
{
//
// Add new SqlParameter to the command.
//
command.Parameters.Add(new SqlParameter("Field", Textbox1.Text)); // I do not recommend using a textbox and letting the user write anything. You have to limit his choices by the fields in your table. Use a dropdownlist and limit his choices by meaningful fields in your "tableBooks" table.
command.Parameters.Add(new SqlParameter("Value", Textbox2.Text));
//
// Read in the SELECT results.
//
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//GET YOUR BOOK
}
}
Please notice my comments :
// I do not recommend using a textbox and letting the user write anything as a "keyword". You have to limit his choices by the columns in your table. Use a dropdownlist and limit his choices by meaningful choices from your "tableBooks" table.

It is more secure to used parameterized query than the form you use already
you can try this, I think it will help
// Declare a connection
conn = new
SqlConnection("Server=.;DataBase=DataBase;Integrated Security=SSPI");
conn.Open();
//Create parameterized query
SqlCommand cmd = new SqlCommand(
"Select * from tableBooks WHERE (case #userCriteria when 'Title' then Title when 'Author' then Author when 'Subject' then Subject when 'ISBN' then ISBN else '' end) LIKE '%'+#keyword+ '%'", conn);
//Create parameter userCriteria
SqlParameter param = new SqlParameter();
param.ParameterName = "#userCriteria";
param.Value = userCriteria;
//Create parameter keyword
SqlParameter param = new SqlParameter();
param.ParameterName = "#keyword";
param.Value = userCriteria;
// add new parameter to command object
cmd.Parameters.Add(param);
// get data stream
reader = cmd.ExecuteReader();
// write each record
while(reader.Read())
{
//Get data
}

Related

Assigning values from access database to string variables

The program works just fine until I add the where clause in the select statement resulting in the code throwing an exception "System.Data.OleDb.OleDbException: 'No value given for one or more required parameters.' " which reffers to "dr=cmd.ExecuteReader()". What can I do make the where clause work as I need this for multiple columns for the table.
I should mention I want to extract from a single row each time, as I want only the information of the current logged user.
public partial class Profil : Form
{
public string utiliz;
public Profil()
{
InitializeComponent();
}
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db_users.mdb");
OleDbCommand cmd = new OleDbCommand();
OleDbDataReader dr;
private void Profil_Load(object sender, EventArgs e)
{
con.Open();
label1.Text = HomePage.current_user;
utiliz = HomePage.current_user;
cmd = new OleDbCommand("SELECT nume FROM tbl_personaldata WHERE utilizator = #utiliz",con);
dr = cmd.ExecuteReader();
while(dr.Read())
txtNume.Text = dr[0].ToString();
}
}
You used a parameter here;
cmd = new OleDbCommand("SELECT nume FROM tbl_personaldata WHERE utilizator = #utiliz",con);
^^^^^
But you didn't add it to the command. In C# simply mentioning the name of a variable in a string is not enough to make any form of interaction between the variable and the string
string name = "John";
Console.WriteLine("I'm called name"); //prints "I'm called name", not "I'm called John"
You have to add the parameter to the command:
cmd.Parameters.AddWithValue("#utiliz", utiliz);
When you have more than one parameter, you must use Add in the order they appear in the SQL
cmd.CommandText = "SELECT * FROM t WHERE a = #a and b = #b";
cmd.Parameters.AddWithValue("#a", "some a");
cmd.Parameters.AddWithValue("#b", "some b");
Even though it understands # is a parameter, the parameter names are ignored with Access/OLE; it's still sensible to use them to help code readability, but the order of addition is critical . In most other databases you'll use in your life, the names are used, and hence you can add parameters in any order so long as the name matches. With other databases you can also reuse the same name in the SQL more than once. If you want to repeat a value in Access SQL, you must perform another Parameters.Add[WithValue] for the same thing:
//yes
cmd.CommandText = "SELECT * FROM t WHERE firstname = #fname or lastname = #lname";
cmd.Parameters.AddWithValue("#fname", "Lee");
cmd.Parameters.AddWithValue("#lname", "Lee");
//no, not in Access. Other DBs are fine with this
cmd.CommandText = "SELECT * FROM t WHERE firstname = #name or lastname = #name";
cmd.Parameters.AddWithValue("#name", "Lee");
If you switch to using SqlServer in future, cease using AddWithValue, but other databases don't necessarily suffer from its use
You need to provide the parameter and its value as it is a parameterized query.
cmd = new OleDbCommand("SELECT nume FROM tbl_personaldata WHERE utilizator = ?",con);
cmd.Parameters.Add("?", OleDbType.VarChar /* Or specify the column type for OleDbType */).Value = utiliz;
Note:
Remarks
OLE DB .NET Provider does not support named parameters for passing parameters to an SQL statement or a stored procedure called by an OleDbCommand when CommandType is set to Text.
In this case, the question mark (?) placeholder must be used.
Reference
OleDbCommand.Parameters Property

Pass GUID into stored procedure method C#

I am mostly new to c# so i am looking for some guidance here. I am testing a method that i need to pass a list of guids to and run a stored procedure that returns values based on the guids i pass to it which i can then print to the console. I can get the method to work when i pass only one guid but when i pass a list of guids it seems to not work.
I feel like i am lacking some understanding here around how i should pass the list of guids and return it. I get conversion errors trying to return List.
Here is how far i have got but i feel like i am stuck now and cant progress anymore from any info i have found online.
class Program
{
static void Main(string[] args)
{
List<Guid> tempguid = new List<Guid>();
tempguid.Add(Guid.Parse("472USFA0-B705-9A73-ABD4-3B1870AF1409"));
tempguid.Add(Guid.Parse("FA97E6BB-0875-5UB9-967A-87ECC396F9F0"));
GetValue(tempguid);
Console.WriteLine(GetValue);
}
public void GetValue(List<Guid> tempguid)
{
using (SqlConnection conn = new SqlConnection("connection string here"))
{
conn.Open();
SqlCommand cmd = new SqlCommand("stored procedure here", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#id", tempguid));
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine((string)rdr["value"]);
}
Console.ReadLine();
}
}
}
}
Should i be passing the list like this GetValue(List tempguid)?
EDIT
ok so if i use a TVP.
Something like:
CREATE TYPE [dbo].[Identity] AS TABLE(
[Id] [uniqueidentifier] NOT NULL
)
GO
Then my procedure will look something along the lines of:
CREATE OR ALTER PROCEDURE [dbo].[procedure_name]
#id dbo.Identity READONLY
as
SELECT t.[id]
,t.[value]
FROM [dbo].[table1] t
Inner Join #id i on i.Id = t.id
How do i use this TVP in c# for my stored procedure?
you need a foreach loop on GUID list. Try like:
foreach (var g in tempguid)
{
cmd.Parameters.Add(new SqlParameter("#id", g));
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine((string)rdr["value"]);
}
Console.ReadLine();
}
cmd.Parameteres.Clear();
}
You can't pass a list to sp. You need to convert your guids into a csv string example:
var param = string.Join(", ", tempguid);
Then
cmd.Parameters.Add(new SqlParameter("#id", param));
Then after receiving your parameter on the sp pass into String_Split. Goodluck!
Passing values to TVPs from ADO .NET is very straightforward, and requires very little extra code compared to passing data to regular parameters.
For the data type you specify SqlDbType.Structured.
You specify the name of the table type in the TypeName property of the parameter.
You set the Value property of the parameter to something suitable.
As mentioned in the above link System.Data.SqlClient supports populating table-valued parameters from DataTable, DbDataReader or IEnumerable<T> \ SqlDataRecord objects.
If you already have the list of Guids coming from other sources in your case tempguid then you could use a datatable to pass the details to stored procedure.
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("Id", typeof(Guid)));
// populate DataTable from your List here
foreach (var id in tempguid)
tvp.Rows.Add(id);
And change the ADO.NET code like below -
conn.Open();
SqlCommand cmd = new SqlCommand("dbo.tvpProcedure", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParameter = new SqlParameter();
tvpParameter.ParameterName = "#id";
tvpParameter.SqlDbType = System.Data.SqlDbType.Structured;
tvpParameter.Value = tvp;
tvpParameter.TypeName = "dbo.testTVP";
cmd.Parameters.Add(tvpParameter);
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine((string)rdr["value"]);
}
Console.ReadLine();
}
Side notes:
Looks like the GUIDs you have shown in the code seems invalid as they contain non-
hexadecimal values.
472USFA0-B705-9A73-ABD4-3B1870AF1409
^^
FA97E6BB-0875-5UB9-967A-87ECC396F9F0
^
Change the Type name something meaningful instead of dbo.Identity in my case I used
dbo.testTVP
Further information -
http://www.sommarskog.se/arrays-in-sql-2008.html

Use SQL command as a parameter value in C#

I have a SQL command I am running that works great however for one of the AddWithValue parameters I want to use another SQL command to get that value... this is what I have but the cmd2 I want to use isn't working. Is it even possible to get data that way in theory it makes sense but it doesn't seem to work..
cmd2 = new SqlCommand("SELECT acctNum FROM custInfo WHERE customerName = #customerName", cn);
cmd2.Parameters.AddWithValue("#customerName", customerDropDown.Text);
cmd = new SqlCommand("UPDATE custInfo SET ctGal = (ctGal - (#contractGallons)) WHERE acctNum = #acctNum", cn);
cmd.Parameters.AddWithValue("#contractGallons", gallonsTextBox.Text)
cmd.Parameters.AddWithValue("#acctNum", cmd2);
I suggested combining both queries into one:
//DONE: let keep query readable
string sql =
#"UPDATE custInfo
SET ctGal = (ctGal - (#contractGallons))
WHERE acctNum IN (SELECT c.acctNum
FROM custInfo c
WHERE c.customerName = #customerName)";
//DONE: wrap IDisposable into using
using (var cmd = new SqlCommand(sql, cn)) {
//TODO: get rid of AddWithValue, but specify the actual fields' types
cmd.Parameters.AddWithValue("#contractGallons", gallonsTextBox.Text);
cmd.Parameters.AddWithValue("#customerName", customerDropDown.Text);
cmd.ExecuteNonQuery();
}
You have two choices if you want to go this route:
Combine the two queries when you instantiate the second SqlCommand. This will require adding a second parameter to the second command.
Or run the first command. Fetch the resulting acctNum and add it as a value for the second command.
Probably better would be to rewrite the two queries into a single joined query.
You must use cmd2.ExecuteReader() to get the acctNum for example
You can try following code
using (SqlDataReader reader = cmd2.ExecuteReader())
{
if (reader.Read())
{
cmd = new SqlCommand(#"UPDATE custInfo SET ctGal = (ctGal -
(#contractGallons)) WHERE acctNum = #acctNum", cn);
cmd.Parameters.AddWithValue("#contractGallons", gallonsTextBox.Text)
cmd.Parameters.AddWithValue("#acctNum", reader["acctNum"]);
}
}
Hope this will help..

MySqlCommand in Asp.net WEB Forms to Display in Label

i have this sql command
string myreg = "select registration_no from truck where truck_id ='" + truckID + "'";
MySqlCommand cmd = new MySqlCommand(myreg, conn);
i want to put the value of myreg to my RegistrationNo.Text label.
i have this RegistrationNo.Text = myreg; and it displays select registration_no from truck where truck_id on my page
You need to read something about the workings of ADO.NET and its providers.
To get the result of that query in your textbox you need
Open a connection to your MySql Server
Prepare a command to send to the Server
Get back the result
Write the result to your textbox
All these passages requires the use of specific classes and some code to glue everything together
// Prepare your command using a parameter placeholder
string myreg = "select registration_no from truck where truck_id =#id";
// Build the connection to the server and build the command to execute
using (MySqlConnection cnn = new MySqlConnection(.... the connection string that identifies your server and db ))
using (MySqlCommand cmd = new MySqlCommand(myreg, cnn))
{
// Open the connection
cnn.Open();
// Add the parameter expected
cmd.Parameters.Add("#id", MySqlDbType.VarChar).Value = truckID;
// Execute the command and get back the return value (if found)
object result = cmd.ExecuteScalar();
// Check if the ExecuteScalar has returned something
if(result != null)
RegistrationNo.Text = result.ToString();
else
... message to your user about the failed search ...
}
PS. I have assumed that your variable truckID is a string because in your original code you have passed it between single quotes, but if it is an integer then you need to modify the parameter type to MySqlDbType.Int32
Also, I have used the ExecuteScalar method instead of ExecuteReader because I think that your query returns just a row with a single column and for this task it is better to use ExecuteScalar
You can use datareader also.See MSDN documentation here.
using (connection)
{
SqlCommand command = new SqlCommand(
"SQL Query",
connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}

How to prevent a SQL Injection escaping strings

I have some queries (to an acccess database) like this :
string comando = "SELECT * FROM ANAGRAFICA WHERE E_MAIL='" + user + "' AND PASSWORD_AZIENDA='" + password + "'";
and I'd like to "escape" user and password, preventing an injection.
How can I do it with C# and .NET 3.5? I'm searching somethings like mysql_escape_string on PHP...
You need to use parameters. Well dont have to but would be preferable.
SqlParameter[] myparm = new SqlParameter[2];
myparm[0] = new SqlParameter("#User",user);
myparm[1] = new SqlParameter("#Pass",password);
string comando = "SELECT * FROM ANAGRAFICA WHERE E_MAIL=#User AND PASSWORD_AZIENDA=#Pass";
Don't escape the strings to start with - use a parameterized query. Benefits of this over escaping:
The code is easier to read
You don't have to rely on getting the escaping correct
It's possible that there are performance improvements (DB-specific etc)
It separates "code" (the SQL) from the data, which is just good sense logically
It means you don't need to worry about data formats for things like numbers and dates/times.
The docs for SqlCommand.Parameters give a good, complete example.
You should use the SQL paramters to prevent SQL Injection
look at the code
//
// The name we are trying to match.
//
string dogName = "Fido";
//
// Use preset string for connection and open it.
//
string connectionString = ConsoleApplication716.Properties.Settings.Default.ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
//
// Description of SQL command:
// 1. It selects all cells from rows matching the name.
// 2. It uses LIKE operator because Name is a Text field.
// 3. #Name must be added as a new SqlParameter.
//
using (SqlCommand command = new SqlCommand("SELECT * FROM Dogs1 WHERE Name LIKE #Name", connection))
{
//
// Add new SqlParameter to the command.
//
command.Parameters.Add(new SqlParameter("Name", dogName));
//
// Read in the SELECT results.
//
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
int weight = reader.GetInt32(0);
string name = reader.GetString(1);
string breed = reader.GetString(2);
Console.WriteLine("Weight = {0}, Name = {1}, Breed = {2}", weight, name, breed);
}
}
}
Yes, you can avoid injection by using Named Parameters
Use parameters instead of escaping strings:
var comando = "SELECT * FROM ANAGRAFICA WHERE E_MAIL=#user AND PASSWORD_AZIENDA=#password";
Then assign values to those parameters before you execute the SqlCommand.
You can check the below link to know how to prevent SQL injection in ASP.Net. I would prefer to use
Using parametrized queries or Stored Procedures.
Validating special characters like '(very dangerous)
http://dotnet.dzone.com/news/aspnet-preventing-sql-injectio
If you can convert these to Named Parameters, I think you would be better served.
#Jethro
You could also write it like this:
SqlParameter[] sqlParams = new SqlParameter[] {
new SqlParameter("#Name", contact.name),
new SqlParameter("#Number", contact.number),
new SqlParameter("#PhotoPath", contact.photoPath),
new SqlParameter("#ID", contact.id)
};
Follow the steps below and resolve the SQL INJECTION problem:
OracleParameter[] tmpParans = new OracleParameter[1];
tmpParans[0] = new Oracle.DataAccess.Client.OracleParameter("#User", txtUser.Text);
string tmpQuery = "SELECT COD_USER, PASS FROM TB_USERS WHERE COD_USER = #User";
OracleCommand tmpComand = new OracleCommand(tmpQuery, yourConnection);
tmpComand.Parameters.AddRange(tmpParans);
OracleDataReader tmpResult = tmpComand.ExecuteReader(CommandBehavior.SingleRow);

Categories

Resources