I am trying to send values to a stored procedure via a listbox containing country names I get them from the database. If I choose one option code works 100% 100%. But if I put 2 or 3 options, I get the following error:
Parameter '#stIdCity' was supplied multiple times.
Line 322: da.Fill(ds);
Full code:
protected void lstBoxTestCity_SelectedIndexChanged(object sender, EventArgs e)
{
string str = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(str))
{
using (SqlCommand cmd = new SqlCommand("Tprocedure", con))
{
cmd.CommandType = CommandType.StoredProcedure;
foreach (ListItem item in lstBoxTestCity.Items)
{
if (item.Selected)
{
cmd.Parameters.AddWithValue("#stIdCity", item.Value);
}
}
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
gvProducts.DataSource = ds;
gvProducts.DataBind();
}
}
}
Stored procedure:
CREATE PROCEDURE Tprocedure
(#stIdCity NVARCHAR(20) = NULL, )
AS
BEGIN
SELECT *
FROM employees
INNER JOIN TCity ON employees.IdstICity = TCity.IdstICity
WHERE (employees.IdstICity IN (SELECT ITEM
FROM dbo.SplitString(#stIdCity, ','))
OR ISNULL(#stIdCity, '') = '')
END
Image of list:
Please help to solve the problem.
Sorry if the question was repeated, but I could not find a solution to it.
You have this:
foreach (ListItem item in lstBoxTestCity.Items)
{
if (item.Selected)
{
cmd.Parameters.AddWithValue("#stIdCity", item.Value);
}
}
so for each selected city, you add a new parameter. That is why you get that error message.
Apparently you want one parameter, with a comma-separated value. So build that:
var value = string.Join(",",lstBoxTestCity.Items.Where(it => it.IsSelected).Select(it => it.Value));
cmd.Parameters.Add("#stIdCity", SqlDbType.NVarChar, 20).Value = value;
First I use LINQ to filter for selected items, then I get their value. string.Join combines the resulting values with commas.
But do note that your stored procedure accepts just a nvarchar(20), so you may run out of space when multiple cities have been selected.
You ONLY have the ONE parmater, and it is a comma delimited string of values.
So, you have to "build up" a comma delimited string. Say like this:
string myparms = "";
foreach (ListItem item in lstBoxTestCity.Items)
{
if (item.Selected)
{
if (myparms != "")
myparms += ",";
myparms += item.Value;
}
}
cmd.Parameters.Add("#stIdCity",SqlDbType.NVarChar).Value = myparms;
So, you only passing one value - but you have to build up the "string" of values to pass.
Related
I have a table which contains a single column "CODE_CAR".
I want to populate this table with list of string as below :
_Connection.Open();
var lst_code_cars = new List<string> { "YH_21", "NM_00", "BAR_N178" };
string cmdText = "INSERT INTO Y157.CARS_IDENDITY(CODE_CAR) VALUES ("+lst_code_cars+")";
MySqlCommand cmd = new MySqlCommand(cmdText, _Connection);
foreach (string cars_code in lst_code_cars )
{
cmd.Parameters.AddWithValue("#"+cars_code , cars_code );
cmd.ExecuteNonQuery();
}
_Connection.Close();
When i try this code, i get error : MySqlException : Parameter '#NM_00' must be defined.
The error tells you exactly what is wrong. You did not define a parameter, you concatenated the value directly into the query string. So don't do that.
_Connection.Open();
var lst_code_cars = new List<string> { "YH_21", "NM_00", "BAR_N178" };
string cmdText = "INSERT INTO Y157.CARS_IDENDITY(CODE_CAR) VALUES (#CarCode)";
MySqlCommand cmd = new MySqlCommand(cmdText, _Connection);
foreach (string cars_code in lst_code_cars )
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#CarCode" , cars_code );
cmd.ExecuteNonQuery();
}
_Connection.Close();
You'll also need to clear the parameters if you mean to re-add them each loop. Either that or add the parameter once and then edit the value in the loop instead of adding a new parameter each time.
Ideally, though, you could write this as a batch insert.
I have this DataSet which calls my Stored Procedure and returns a list of integers. How can I extract the list of integers which I could store in a variable be it a collection which grows in size such as a List<T> or a primitive data type like an array of integers.
Below is my code:
private DataSet getSubGroupsBelongingToUser()
{
DataTable variable;
DataSet DS;
myConnectionString = ConfigurationManager.ConnectionStrings["FSK_ServiceMonitor_Users_Management.Properties.Settings.FSK_ServiceMonitorConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
SqlParameter param = new SqlParameter("#UserId", getUserID(cbxSelectUser.Text));
DS = GetData("Test", param);
variable = DS.Tables[0];
}
return DS;
}
When I hover over the DS magnifier (refer to image):
I want to retrieve and store that list of integers somewhere. How can I go about doing this? All the examples I came across online make use of linq and that is not applicable here since I am getting the results from my stored procedure which requires one input parameter. Here is the definition of the stored procedure below:
create proc [dbo].[Test]
#UserId smallint
as
begin
select DepartmentSubGroupId from DepartmentSubGroupUser
where UserId= #UserId
end
GO
So essentially when you pass in a UserId, you should get those values. I am using SQL Server as my DBMS.
The simplest and most efficient approach would be to not use a DataSet/DataTable at all:
private List<int> GetSubGroupsBelongingToUser()
{
List<int> list = new List<int>();
using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["FSK_ServiceMonitor_Users_Management.Properties.Settings.FSK_ServiceMonitorConnectionString"].ConnectionString))
using (var cmd = new SqlCommand("Test", con))
{
cmd.CommandType = CommandType.StoredProcedure;
var param = new SqlParameter("#UserId", SqlDbType.Int).Value = int.Parse(cbxSelectUser.Text);
cmd.Parameters.Add(param);
con.Open();
using (var rd = cmd.ExecuteReader())
{
while (rd.Read()) list.Add(rd.GetInt32(0));
}
} // no need to close the connection with the using
return list;
}
If you insist on the DataTable, at least it's more conscise:
return DS.Tables[0].AsEnumerable().Select(r => r.Field<int>(0)).ToList();
As #David pointed out the simplest option would be to use a SqlDataReader and loop through all the records.
However, if your heart is set on DataTables then all you need to do is to iterate all rows from the result table, grab the value from column DepartmentSubGroupId and add it to a list. You can do that with Linq also like this:
return DS.Tables[0].Rows
.Cast<DataRow>() // Rows is an ICollection and you need to cast each item
.Select(r => (int)r["DepartmentSubGroupId"]) // For each row get the value from column DepartmentSubGroupId
.ToList();
Before I saw #Tim's solution, I had already prepared this (which works just as well as most of the above solutions):
public List<int> getSubGroupsBelongingToUser()
{
List<int> DepartmentSubGroupIds = new List<int>();
myConnectionString = ConfigurationManager.ConnectionStrings["FSK_ServiceMonitor_Users_Management.Properties.Settings.FSK_ServiceMonitorConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
SqlParameter parameter = new SqlParameter("#UserId", getUserID(cbxSelectUser.Text));
mySQLCommand = new SqlCommand("Test", mySQLConnection);
mySQLCommand.CommandType = CommandType.StoredProcedure;
mySQLCommand.Parameters.Add(parameter);
mySQLConnection.ConnectionString = myConnectionString;
mySQLConnection.Open();
SqlDataReader sqlDataReader = mySQLCommand.ExecuteReader();
while (sqlDataReader.Read())
{
DepartmentSubGroupIds.Add(Convert.ToInt32(sqlDataReader["DepartmentSubGroupId"]));
}
}
return DepartmentSubGroupIds;
}
Thanks everybody, much appreciated.
I am working on my windows form applications. In this winform, I have a checkListBox which binded the data from my sql db. I am trying to match the checkListBox's checkedItem to my sql table column's text which is stored as a nvarchar data type. I ran the debug mode and found out that it skip the entire while loop when the program is executed. I have no idea why because the valuable name items did actually showed which checkbox in checkListBox is checked
This is my code.
foreach(var items in checkListBox1.CheckedItems){
string query = "select * from my_table WHERE employeeName = '"+items+"'"
SqlCommand myCommand = new SqlCommand(query, myConn);
SqlDataReader dr = myCommand.ExecuteReader();
while(dr.Read()){
//read the column
}
}
Here is the screen Shot. I tried to fetch the chineseName in the column (don't worry about what it is lol)
You have multiple problems in your code. You don't need to write your query in ForEach loop. And if you are expecting to get multiple values from your checklistbox then equalto = operator is not your friend, you would need to use IN operator. Now check below example.
private void button1_Click(object sender, EventArgs e)
{
string items = string.Empty;
foreach (var item in checkedListBox1.CheckedItems)
{
if (items.Length == 0)
items = item.ToString();
else
items = items + "," + item;
}
//make myCommand object and open connection on your own
myCommand = new SqlCommand(query, myConn);
string query = #'select distinct firstName, lastName, chineseName, teacherEmail, entryYear, leaveYear, userLoginId, ad.applicationId
from [teacher_detail] as td
LEFT JOIN[class_detail] as cd ON td.teacherId = cd.teacherId
LEFT JOIN[application_teacher] as at ON at.teacherId = td.teacherId
LEFT JOIN[application_detail] as ad ON at.applicationId = ad.applicationId
Where ad.applicationId = 2
and chineseName in (#name)'
myCommand.Parameters.Add("#name", SqlDbType.nvarchar);
myCommand.Parameters["#name"].Value = items;
//now execute query
}
As Data type in database is nvarchar try it by modifying the following statement in your code
string query = "select * from my_table WHERE employeeName = '"+items+"'"
to
string query = "select * from my_table WHERE employeeName = N'"+items.ToString()+"'"
Prefix 'N' is used for the value to compare from checked item
Not sure if this is written correctly but it looks correct. I am wanting to update a record if the id already exists and insert if not.
DataSet ds = new DataSet();
ds.ReadXml(XDocument.Load(Application.StartupPath + #"\xml1.xml").CreateReader());
using (var conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + Application.StartupPath + "\\Database3.mdb"))
{
conn.Open();
// make two commands here
var commInsert = new OleDbCommand("Insert INTO Table1 (description, active) VALUES (#iq_question,#active);", conn);
var commUpdate = new OleDbCommand("UPDATE Table1 SET description=#iq_question,active=#active WHERE ID=#question_id;", conn);
// here add your parameters with no value
//string question_id = row[0].ToString();
//string iq_question = row[1].ToString();
//string active = row[4].ToString();
commInsert.Parameters.Add(new OleDbParameter("#iq_question", OleDbType.VarChar));
commInsert.Parameters.Add(new OleDbParameter("#active", OleDbType.VarChar));
commUpdate.Parameters.Add(new OleDbParameter("#question_id", OleDbType.AutoNumber));
commUpdate.Parameters.Add(new OleDbParameter("#iq_question", OleDbType.Text));
commUpdate.Parameters.Add(new OleDbParameter("#active", OleDbType.Text));
foreach (DataTable table in ds.Tables)
{
foreach (DataRow row in table.Rows)
{
// here only reset the values
commUpdate.Parameters["#question_id"].Value = row[0].ToString();
commUpdate.Parameters["#iq_question"].Value = row[1].ToString();
commUpdate.Parameters["#active"].Value = row[4].ToString();
int recs = commUpdate.ExecuteNonQuery();
if (recs < 1) // when no records updated do insert
{
commInsert.Parameters["#iq_question"].Value = row[1].ToString();
commInsert.Parameters["#active"].Value = row[4].ToString();
commInsert.ExecuteNonQuery();
}
}
}
commInsert.Dispose();
commUpdate.Dispose();
conn.Close();
}
System.Windows.Forms.MessageBox.Show("Updated Latest Data Was Succesfull");
I either get an error on the insert saying it will create duplicate content, or it creates more rows with different data. So say I should be getting 10 rows from the xml file, the first time I run it I get the 10 rows with the correct data. If I run it again, I end up with 10 more so being 20 but the last 10 rows show different data. I don't think I am identifying the rows in the xml file correctly and I need to do some research on that part.
There is no Exists for MS Access. The engine is much more primitive than Sql Server. See here: Microsoft Access SQL. I think, what you can do is:
myCommand.CommandText = "UPDATE Table1 SET description=#iq_question,active=#active WHERE ID=#currentRow";
......
int recs = myCommand.ExecuteNonQuery();
if (recs < 1) // when no records updated do insert
{
myCommand.Parameters.Clear();
myCommand.CommandText = "Insert INTO Table1 VALUES(#iq_question,#active)";
.....
}
This is still 2 statements but you can save some coding by not doing Select first. Because ExecuteNonQuery will tell you if you updated anything
Another thing is that your code is a bit inefficient. You have nested loop where you can reuse same command and connection. Yuu can do this
using (var conn = new OleDbConnection(.......))
{
conn.Open();
// make two commands here
var commInsert = new OleDbCommand(.....);
var commUpdate = new OleDbCommand(.....);
// here add your parameters with no value
commInsert.Parameters.Add(new OleDbParameter(....));
.......
Foreach (....)
{
Foreach (....)
{
// here only reset the values
commUpdate.Parameters[0].Value = ...
...
int recs = commUpdate.ExecuteNonQuery();
if (recs < 1) // when no records updated do insert
{
commInsert.Parameters[0].Value = iq_question;
.....
}
}
}
commInsert.Dispose();
commUpdate.Dispose();
}
You can also use nested using for commands. Only setting values will be more efficient to what you do right now.
I am inserting a web form into the database and so using parameterized queries. I have a CheckBoxList. How can I iterate over CheckBoxList, create an insert statement for every checked thing (many-to-many), and keep this parameterized and executed in one swoop?
I have this right now:
string query = "INSERT INTO resources (url, submitted_by, author_name) VALUES (#url, #submitted_by, #author_name);";
foreach (ListItem li in CheckBoxList1.Items)
{
if (li.Selected = true)
{
query += "; INSERT INTO ";
}
}
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("#url", TextBox1.Text);
cmd.Parameters.AddWithValue("#submitted_by", TextBox2.Text);
cmd.Parameters.AddWithValue("#author_name", TextBox3.Text);
try
{
conn.Open();
cmd.ExecuteNonQuery();
Label1.Text = "Added to database.";
}
As you can see it's unfinished. Any suggestions?
You could use LINQ to generate unique named parameters for each item in your collection, then add the associated values in later:
var builder = new StringBuilder();
var listParams = CheckBoxList1.Items
.Where(li => li.Selected)
.Select(li, idx => new
{
PhoneString = String.Format("#phone_id{0}", idx),
PhoneValue = GetPhoneId(li),
ResourceString = String.Format("#resource_id{0}", idx),
ResourceValue = GetResourceId(li)
};
foreach (var param in listParams)
{
builder.AppendFormat("INSERT INTO phones_resources (phone_id, resource_id)
VALUES ({0}, {1});",
param.PhoneString, param.ResourceString);
}
SqlCommand cmd = new SqlCommand(builder.ToString(), conn);
foreach (var param in listParams)
{
cmd.Parameters.AddWithValue(param.PhoneString, param.PhoneValue);
cmd.Parameters.AddWithValue(param.ResourceString, param.ResourceValue);
}
I'm assuming you have some way of getting associated phone_id, resource_id from any given ListItem - you can just plug that in where I've put the placeholder Get___ functions.
Note: Switched to a StringBuilder - it's much better than building up a string with repeated +=.