Update a column in the database, from a list - c#

I am trying to update a column in the database, from a list
command = new SqlCommand("update Login_Users set Password=#a where UserName !='" + null + "'", Db);
Db.Open();
for (int i = 0; i < list.Count; i++)
{
list[i] = Encrypt(list[i]);
command.Parameters.AddWithValue("#a",list[i]);
int a = command.ExecuteNonQuery();
}
but I get this error:
variable name already been declared

Your command only has one parameter, but you are attempting to add a new one through each loop (via AddWithValue ... add with value).
Either put the command declaration in the loop (as below), or use one of the other methods to update the value.
Db.Open();
for (int i = 0; i < list.Count; i++)
{
command = new SqlCommand("update Login_Users set Password=#a where UserName !='" + null + "'", Db);
list[i] = Encrypt(list[i]);
command.Parameters.AddWithValue("#a",list[i]);
int a = command.ExecuteNonQuery();
}

In query you have one parameter called #a - check if your list has only one item. If not that's problem. Meybe it will be better to remove for loop and assign all parameters manually.
Why in query you do something like this:
where UserName !='" + null + "'"
I think much more readable is like this:
where UserName !=''
or
where UserName <>''

You have setup your SqlCommand with a SQL statement that includes a parameter #a. With that set, you can call the command multiple times via the ExecuteQuery after setting the parameter #a to different values.
Within your for loop, the statement command.Parameters.AddWithValue() is potentially adding to the command additional parameter, but no two parameters can have the same value so if your loop is executed more than once, you'll get the error you received.
Your SQL statement appears to be setting the password of all records in Login_Users to some encrypted value multiple times based on your list. If I understand correctly, maybe this would do what you want:
var command = new SqlCommand("update Login_Users set Password=#a where UserName !='" + null + "'", Db);
Db.Open();
command.Parameters.Add(new SqlParameter("#a",null));
for (int i = 0; i < list.Count; i++)
{
cmd.Parameters["#a"].Value = Encrypt(list[i]);
int a = command.ExecuteNonQuery();
}
Good luck!

Related

update a table by using for loop with parameters in C#

I have a table with some columns like
now I want to use a for loop to set
out_0 = 0,
out_1 = 1,
out_2 = 2,
out_3 = 3,
out_4 = 4
so I update it with such code as
string sql = "update exchange_out set #column = #id where member_id = 6;";
SqlCommand cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#column", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
int n = 0;
for (int i = 0; i < 5; i++)
{
cmd.Parameters["#column"].Value = "out_" + i;
cmd.Parameters["#gid"].Value = i;
n = cmd.ExecuteNonQuery();
MessageBox.Show("" + n);
}
but it didn't write any data into the table while it literally did five times of updating, because the messagebox returns "1" five times.
finally I solve this by
for (int i = 0; i < 5; i++){
sql = string.Format("update exchange_out set {0} = {1} where member_id = 6", "out_" + i, i);
}
but I'm still wondering why it didn't work by adding parameters?
any respond will be appreciated. :)
I'm still wondering why it didn't work by adding parameters?
Identifiers such as table and column names cannot be parameterized in this way, only data. Your attempt effectively runs a query like this:
update exchange_out set 'out_1' = 1 where member_id = 6;
It's the same in any programming language:
var data1 = "hello";
var whichData = "1";
Console.WriteLine(data+whichData); //it doesn't compile; you cannot programmatically build a variable name `data1` in this way
The way you found is reasonably the only way but you should still parameterize the data:
using var cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#data", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
for (int i = 0; i < 5; i++){
sql = string.Format("update exchange_out set out_{0} = #data where member_id = #id", i);
cmd.CommandText = sql;
cmd.Parameters["#data"].Value = ...
cmd.Parameters["#id].Value = 6;
...
You could also start with an SQL stub like "UPDATE t SET " and repeatedly concatenate on identifiers and parameters:
using var cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#data", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
var sql = "UPDATE exchange_out SET ";
for (int i = 0; i < 5; i++){
sql += string.Format("out_{0} = #data{0},", i);
cmd.Parameters["#data"+i].Value = ...
}
sql = sql.TrimEnd(',');
sql += " where member_id = #id";
cmd.Parameters["#id"].Value = 6;
cmd.CommandText = sql;
...
This does the update in one operation, running a query like UPDATE t SET out_1 = #data1, out_2 = #data2 ...
These are safe from SQL injection because your code controls the entire SQL; there isn't any capacity for a user to provide '; DROP TABLE Students;-- as the {0} going into the identifier in this case but take care that you don't arrange for it to be possible (don't let the user provide identifier text)..
Your non-parameter attempt is also safe from SQL injection in this case by virtue of inserting intergers that you control, rather than strings you don't, but be careful you don't universally apply the technique and one day include user-suppied strings. If you do find yourself in that suitable you should use something like a whitelist of user input - any string identifier provided by the user that isn't whitelisted should not be put in the SQL

How to create dynamic parameters in SQL Server stored procedure

I have a form that generate inputs dynamically, then I get their values and generate command parameters dynamically.
SqlConnection con = new SqlConnection(cs);
SqlCommand cmd =new SqlCommand("insert_op",con);
cmd.CommandType = CommandType.StoredProcedure;
for (int i = 0; i < Request.Form.Count; i++)
{
if (Request.Form["frm_option" + (i + 1)] != null)
{
cmd.Parameters.AddWithValue("#op" + i, Request.Form["frm_option" + (i + 1)]);
}
}
try
{
using (con)
{
con.Open();
cmd.ExecuteNonQuery();
}
}
catch
{
}
How can I pass these dynamic parameters to SQL Server stored procedure and how should stored procedure be?
First of all, this isn't the right design.
To achieve your goal you need to pass multiple values in SQL statment as follows
SQL
INSERT INTO tbl_options(op_name) VALUES (value1),(value2),...(nthValue)
Code
Your code will be something like this
string command = "INSERT INTO tbl_options(op_name) VALUES";
for (int i = 0; i < Request.Form.Count; i++)
{
if (Request.Form["frm_option" + (i + 1)] != null)
{
command += "(#op" + i + "),";
cmd.Parameters.AddWithValue("#op" + i, Request.Form["frm_option" + (i + 1)]);
}
}
If you want to "insert each parameter into separate row" then perhaps it is better to use table variable as a stored prosedure parameter?
Your User Defined Table Type and stored procedure might look like:
create type dbo.ValueTableType as table (Value varchar(255))
GO
create procedure dbo.InsertValues
#Values dbo.ValueTableType readonly
as
begin
insert into dbo.YourTable (Value)
select Value from #Values;
end
See this ADO.NET example of how to initialize and pass a table parameter to stored procedure https://stackoverflow.com/a/10409710/623190
You can provide defaults for every field in the table, so any parameters you do not pass in will get the default. Here I demonstrate defaults of NULL.
CREATE PROCEDURE [dbo].[sproc_tbl_options_Insert]
#op_name nvarchar(50) = NULL,
#op_somethingelse nvarchar(5) = NULL,
#op_number int = NULL
AS
BEGIN
INSERT INTO [tbl_options] (op_name, op_somethingelse, op_number)
VALUES (#op_name, #op_somethingelse, #op_number);
END

.Net MySql User Defined Variable as Output Parameter

I've been searching for a while but the answers I find usually involve stored procedures or different functionality.
I am trying to execute a reader and also return a scalar in the one query. I thought I could do this using an output parameter, but I get an exception to check my syntax near NULL = #rows_found(), so it appears the output parameter is not getting initialized.
Basically I need to know if this is possible as I haven't found a code sample like this that works.
command.CommandText = #"
SELECT SQL_CALC_FOUND_ROWS
accounting.*
FROM
accounting
WHERE
transaction_type = #transaction_type
LIMIT
#index, #results;
SET #total_rows = FOUND_ROWS();
";
command.Parameters.AddWithValue("transaction_type", transaction_type);
command.Parameters.AddWithValue("index", index);
command.Parameters.AddWithValue("results", results);
MySqlParameter totalRows = new MySqlParameter("total_rows", 0);
totalRows.Direction = System.Data.ParameterDirection.Output;
command.Parameters.Add(totalRows);
using (MySqlDataReader dr = command.ExecuteReader())
{
while (dr.Read())
invoices.Add(new AccountingDataModel(dr));
}
invoices.Total = (int)totalRows.Value;
cmd.Parameters["#output"].Value.ToString()
Use command object to access your out parameter ....
you can not access out perameter directly.
You Should use like
invoices.Total = Convert.ToInt32(command.Parameters["total_rows"].Value.ToString())
example for stored procedure
MySqlCommand cmd = new MySqlCommand(nameOfStoredRoutine, connection);
cmd.CommandType = CommandType.StoredProcedure;
//input parameters
for (int i = 0; i < (parameterValue.Length / 2); i++)
{
cmd.Parameters.AddWithValue(parameterValue[i, 0], parameterValue[i, 1]);
cmd.Parameters[parameterValue[i, 0]].Direction = ParameterDirection.Input;
parameterList = parameterList + parameterValue[i,0] + " " + parameterValue[i,1] + " ";
}
//single output parameter
cmd.Parameters.AddWithValue("#output", MySqlDbType.Int32);
cmd.Parameters["#output"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery(); //Execute command
return Convert.ToInt32(cmd.Parameters["#output"].Value.ToString());
It seems that this is not possible. From the documentation of MySqlParameter's members for the Direction property:
Gets or sets a value indicating whether the parameter is input-only, output-only, bidirectional, or a stored procedure return value parameter. As of MySQL version 4.1 and earlier, input-only is the only valid choice.
So the parameter is, no matter what you set Direction to, always an input parameter. If you change the value from null to anything else (e.g. 15) you should see that the generated query is something like
SET 15 = FOUND_ROWS()
Eventually i ended up running two queries. Probably this is not as performant as it could be, but at least it gets the desired result (using EF Core):
using (var context = new MyDbContext(...))
{
context.Database.OpenConnection();
var estates = context.MySet
.FromSql("SELECT SQL_CALC_FOUND_ROWS * FROM myset LIMIT 25 OFFSET 25")
.ToList();
var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "SELECT FOUND_ROWS()";
var rows = (long)cmd.ExecuteScalar();
context.Database.CloseConnection();
}

Sql query execution inside a for loop

for (int i = 0; i <= GridView1.Rows.Count - 1; i++)
{
string toemail = GridView1.Rows[i].Cells[2].Text;
string FID1 = GridView1.Rows[i].Cells[0].Text;
GridViewRow row = GridView1.Rows[i];
CheckBox Ckbox = (CheckBox)row.FindControl("CheckBoxMark1");
if (Ckbox.Checked == true)
{
sendMail(toemail);
//ClientScript.RegisterStartupScript(Page.GetType(), "validation", "<script language='javascript'>alert('Email send Succesfully')</script>");
ClientScript.RegisterStartupScript(Page.GetType(), "validation", "<script language='javascript'>alert('Email sent Succesfully on " + test + "')</script>");
cn1.Open();
//cmd4.CommandText = "Insert into TrackingFaculty_det (EmailsentDate) values (#EmailsentDate) WHERE FID=#FID";
cmd4.CommandText = "update TrackingFaculty_det SET EmailsentDate=#Email WHERE FID=#FID ";
cmd4.CommandType = CommandType.Text;
cmd4.Connection = cn1;
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4.Parameters["#Email"].Value = sdt;
cmd4.Parameters.Add("#FID",SqlDbType.VarChar,10);
cmd4.Parameters["#FID"].Value = FID1;
cmd4.ExecuteNonQuery();
cn1.Close();
}
}
//This is a part of c# code along with asp.net
The problem arises if whenever the for loop gets executed the updation should be done in the database but when for loop executes more than once the update query will give a error as The variable name '#Email' has already been declared. Variable names must be unique within a query batch or stored procedure..Any solution for this?
Just move the invariant part of your loop outside the loop. That means, the initialization of the SqlCommand, the opening of the connection and the creation of the parameters collection.
Then inside the loop just change the value of the parameters and execute. (This will be always faster than recreating the same list of parameters inside the loop)
SqlCommand cmd4 = new SqlCommand("update TrackingFaculty_det " +
"SET EmailsentDate=#Email WHERE FID=#FID", cn1);
cn1.Open();
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4.Parameters.Add("#FID",SqlDbType.VarChar,10);
for (int i = 0; i <= GridView1.Rows.Count - 1; i++)
{
.....
if (Ckbox.Checked == true)
{
....
cmd4.Parameters["#Email"].Value = sdt;
cmd4.Parameters["#FID"].Value = FID1;
cmd4.ExecuteNonQuery();
}
}
cn1.Close();
Try clearing command parameters -
cmd4.Parameters.Clear();
and then add the parameter
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
So your final code would be-
cmd4.Parameters.Clear(); // <- Just add this line
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4 object should be refreshed everytime.
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4.Parameters["#Email"].Value = sdt;
cmd4.Parameters.Add("#FID",SqlDbType.VarChar,10);
cmd4.Parameters["#FID"].Value = FID1;
your adding the same parameters more than one time to parameter list of "cmd4"
Clear your paramters before adding once again same parameters
cmd4.Parameters.Clear();
check the Run Stored Procedure with table data as parameter
or second is create string with below example and exec(string) in sql server
sqlstr= "update TrackingFaculty_det SET EmailsentDate=2#2.com WHERE FID=1; update TrackingFaculty_det SET EmailsentDate=1#1.com WHERE FID=#FID ;pdate TrackingFaculty_det SET EmailsentDate=2#2.com WHERE FID=1;"

How to query from SQL comparing with array members?

So I have an array containing computer names called hostnames[].
Contains: compname1, compname2, compname3 etc.
Actually it gets it's members from another SQL query.
I have a data table and I need to query all rows where hostname column has any of the computer names in my array.
something like:
select * from table where hostname in hostnames[]
How should I proceed to achieve my goal?
EDIT:
I was thinking on the below:
string temp = "'" + hostnames[0] + "'";
for(int i=1; i<hostnames[].Lenght; i++)
{
temp = temp + ",'" + hostnames[i] + "'";
}
string query = "SELECT * FROM table WHERE hostname IN (" + temp + ")";
The best way to use parameters for an IN clause is to use Table-valued parameters, in your case you will need a type as a table with one nvarchar column. I've used a generic name so the type can be reused without confusion:
CREATE TYPE dbo.StringList AS TABLE (value NVARCHAR(MAX));
Then it is simply a case of adding your values to a DataTable and passing this as a parameter to your select command:
var dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn("Value", typeof(string)));
for (int i = 0; i < hostnames.Length; i++)
{
var dr = dataTable.NewRow();
dr[0] = "";
dataTable.Rows.Add(dr);
}
using (var connection = new SqlConnection("connectionString"))
using (var command = new SqlCommand("SELECT * FROM Table WHERE HostName IN (SELECT Value FROM #StringList)", connection))
{
SqlParameter stringListParameter = new SqlParameter("#StringList", SqlDbType.Structured);
stringListParameter.Value = dataTable;
stringListParameter.TypeName = "dbo.StringList";
command.Parameters.Add(stringListParameter);
// OPEN CONNECTION EXECUTE COMMAND ETC
}
There are 4 ways to achieve what you want. You choose what works best for you.
Use IN as in your code
Break down to OR. A IN (1, 2, 3) => A=1 OR A=2 OR A=3
Use Table Valued Parameters
User the sql query passed earlier. ex: "SELECT * FROM table WHERE hostname IN (Select hostname from tableusedEarlier)"

Categories