In ADO.Net, iterating over a loop inside a sql connection is causing error - sql

I am writing a program to maintain an inventory of medicine in our store.
I have a Add to cart list, which opens up the SQL connection and delete 1 quantity from the entire stock where the parameter is #medicine
My addToCart listBox's code looks like this
using (SqlConnection conn = new SqlConnection(cstring))
{
using(SqlCommand cmd = new SqlCommand("Update Medicine set Quantity = Quantity - 1 where Name = #medicine", conn))
{
conn.Open();
foreach(string item in cartMedicine)
{
cmd.Parameters.AddWithValue("#medicine", item);
cmd.ExecuteNonQuery();
}
conn.Close();
listMedicine.Items.Clear();
}
}
Now I want to loop my cartMedicine list to get all the names stored in the listbox one by one. But I am getting the error message that,
The variable name '#medicine' has already been declared. Variable names
must be unique within a query batch or stored procedure.'
How can I use the same logic of giving an Adhoc statement each time for each inventory in my Item's list?

Don't add the parameter over and over again but add it once and then just set its value. "AddWithValue is Evil" anyway.
...
SqlParameter sqlParameter = cmd.Parameters.Add("#medicine", SqlDbType.<data type>, <length>)
foreach (string item in cartMedicine)
{
sqlParameter.Value = item;
cmd.ExecuteNonQuery();
}
...
Replace <data type> and <length> with the proper values for the data type of medicine.quantity in the database.

Related

Getting Exception in Summing the values of a column of a table in SQL using ASP.Net

I am trying to add the values of a column of a table. My table looks like this:
enter image description here
I want to add the values of months column for a specific id. My code looks like this:
public int MonthSum(int id)
{
SqlConnection connection = new SqlConnection(connectionString);
string query = "select sum(months) from PayTable where ID=#ID group by ID";
SqlCommand command = new SqlCommand(query,connection);
command.Parameters.Clear();
command.Parameters.Add("ID", SqlDbType.Int);
command.Parameters["ID"].Value = id;
connection.Open();
int total = (int)command.ExecuteScalar();
connection.Close();
return total;
}
Why I am getting exception here??
Since you don't provide more information about the exception, it's only guessing, but you may have a problem adding the parameter as "ID" instead of "#ID". I think that SqlCommand expects the name with the #.
Here some Microsoft documentation with an example very similar to what you are doing.

Oracle Parameters in .net sql queries - ORA-00933: SQL command not properly ended

I am trying to do create a where clause to pass as a parameter to an Oracle command and it's proving to be more difficult than I thought. What I want to do is create a big where query based off user input from our application. That where query is to be the single parameter for the statement and will have multiple AND, OR conditions in it. This code here works however isn't exactly what I require:
string conStr = "User Id=testschema;Password=pass12341;Data Source=orapdex01";
Console.WriteLine("About to connect to Database with Connection String: " + conStr);
OracleConnection con = new OracleConnection(conStr);
con.Open();
Console.WriteLine("Connected to the Database..." + Environment.NewLine + "Press enter to continue");
Console.ReadLine();
// Assume the connection is correct because it works already without the parameterization
String block = "SELECT * FROM TEMP_VIEW WHERE NAME = :1";
// set command to create anonymous PL/SQL block
OracleCommand cmd = new OracleCommand();
cmd.CommandText = block;
cmd.Connection = con;
// since execurting anonymous pl/sql blcok, setting the command type
// as text instead of stored procedure
cmd.CommandType = CommandType.Text;
// Setting Oracle Parameter
// Bind the parameter as OracleDBType.Varchar2
OracleParameter param = cmd.Parameters.Add("whereTxt", OracleDbType.Varchar2);
param.Direction = ParameterDirection.Input;
param.Value = "MY VALUE";
// Get returned values from select statement
OracleDataReader dr = cmd.ExecuteReader();
// Read the identifier for each result and display it
while (dr.Read())
{
Console.WriteLine(dr.GetValue(0));
}
Console.WriteLine("Selected successfully !");
Console.WriteLine("");
Console.WriteLine("***********************************************************");
Console.ReadKey();
If I change the lines below to be the type of result I want then I get an error "ORA-00933: SQL command not properly ended":
String block = "SELECT * FROM TEMP_VIEW :1";
...
...
param.Value = "WHERE NAME = 'MY VALUE' AND ID = 5929";
My question is how do I accomplish adding my big where query dynamically without causing this error?
Sadly there is no easy way to achieve this.
One thing you will need to understand with parameterised SQL in general is that bind parameters can only be used for values, such as strings, numbers or dates. You cannot put bits of SQL in them, such as column names or WHERE clauses.
Once the database has the SQL text, it will attempt to parse it and figure out whether it is valid, and it will do this without taking any look at the bind parameter values. It won't be able to execute the SQL without all of the values.
The SQL string SELECT * FROM TEMP_VIEW :1 can never be valid, as Oracle isn't expecting a value to immediately follow FROM TEMP_VIEW.
You will need to build up your SQL as a string and also build up the list of bind parameters at the same time. If you find that you need to add a condition on the column NAME, you add WHERE NAME = :1 to the SQL string and a parameter with name :1 and the value you wish to add. If you have a second condition to add, you append AND ID = :2 to the SQL string and a parameter with name :2.
Hopefully the following code should explain a little better:
// Initialise SQL string and parameter list.
String sql = "SELECT * FROM DUAL";
var oracleParams = new List<OracleParameter>();
// Build up SQL string and list of parameters.
// (There's only one in this somewhat simplistic example. If you have
// more than one parameter, it might be easier to start the query with
// "SELECT ... FROM some_table WHERE 1=1" and then append
// " AND some_column = :1" or similar. Don't forget to add spaces!)
sql += " WHERE DUMMY = :1";
oracleParams.Add(new OracleParameter(":1", OracleDbType.Varchar2, "X", ParameterDirection.Input));
using (var connection = new OracleConnection() { ConnectionString = "..."})
{
connection.Open();
// Create the command, setting the SQL text and the parameters.
var command = new OracleCommand(sql, connection);
command.Parameters.AddRange(oracleParams.ToArray());
using (OracleDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Do stuff with the data read...
}
}
}

GetOleDbSchemaTable(OleDbSchemaGuid.Indexes, ...) always returning zero rows access database

When querying an Access 2000 database, using:
schemaTable = cn.GetOleDbSchemaTable(OleDbSchemaGuid.Indexes, New Object() {Nothing, Nothing, tableName})
Where cn is a valid and open connection, schemaTable always contains zero rows, despite the tableName specified having many indexes.
This documentation, here http://msdn.microsoft.com/en-us/library/cc668764.aspx suggests that MS Access provides this information.
What gives?
It appears that when retrieving .Indexes the third member of the restrictions array corresponds to the Index name, not the Table name. So to retrieve the indexes for a given table it looks like we need to retrieve all of the indexes (no restrictions) and then filter out the ones we don't want.
The following C# code works for me:
using (OleDbConnection con = new OleDbConnection())
{
con.ConnectionString = myConnectionString;
con.Open();
object[] restrictions = new object[3];
System.Data.DataTable table = con.GetOleDbSchemaTable(OleDbSchemaGuid.Indexes, restrictions);
// Display the contents of the table.
foreach (System.Data.DataRow row in table.Rows)
{
string tableName = row[2].ToString();
if (tableName == "Clients")
{
foreach (System.Data.DataColumn col in table.Columns)
{
Console.WriteLine("{0} = {1}",
col.ColumnName, row[col]);
}
Console.WriteLine("============================");
}
}
con.Close();
}

error in the syntax of cmd parameters

hi guyz in this method i m just adding the values to the db.
temp is a object.
the field value and variables in the object re havin the same name..
dono y this error s comin
plz
help me out...
public virtual void Save_input_parameter_details(Test_Unit_BLL temp )
{
SqlConnection con;
con = new SqlConnection("Data Source=VV;Initial Catalog=testingtool;User ID=sa;Password=sa;");
con.Open();
SqlCommand cmd, cmd2, cmd3;
//try
//{
for (int i = 0; i < temp.No_Input_parameters; i++)
{
cmd2 = new SqlCommand("insert into Input_parameter_details values(#Input_Parameter_name,#Input_Parameter_datatype,#noparams,#class_code", con);
cmd2.Parameters.AddWithValue("#Input_Parameter_datatype", temp.Input_Parameter_datatype[i]);
cmd2.Parameters.AddWithValue("#Input_Parameter_name", temp.Input_Parameter_name[i]);
cmd2.Parameters.AddWithValue("#noparams", temp.No_Input_parameters);
cmd2.Parameters.AddWithValue("#class_code",temp.class_code);
cmd2.ExecuteNonQuery();
}
//}
//catch (Exception ex)
// {
// MessageBox.Show("error"+ex);
// }
}
It may be failing based on the unknown actual sequence of columns its trying to push the data into. You are implying the first X number of columns. You may need to be explicit in your SQL such as :
insert into YourTable ( Fld1, Fld2, Fld3 ) values (#ParmVal1, #ParmVal2, #ParmVal3 );
Then do your parameters.add with values... Additionally, you MAY want to make sure your added parameters are in the same sequence as your SQL statement lists them too.
Do the columns in the table line up with the parameters as you have them listed (1st = input_parameter_name, 2nd = input_parameter_datatype, etc.)?

How do you access data that has been inserted using a ADO.NET transaction?

I'm trying to get the data that has been successfully input into the database via ADO.NET transaction.
Once you've called trans.Commit() there doesn't seem to be a way of getting back the data that has been committed since all identity columns that were created during the transaction are 'virtual' since it is an offline dataset until commit
Many thanks
[EDIT]
Ahh, the problem is, I can't do a reselect as I don't have anything unique to select on other than the identity of the data inserted as part of the transaction.
I can't get the last entered item as this is a multiuser system
Code Sample from a book, not the code in question, but good enough to illustrate what I need:
using System.Data;
using System.Data.SqlClient;
namespace DataAdapterTransaction
{
class Program
{
private static string sqlConnectString = "Data Source=(local);" +
"Integrated security=SSPI;Initial Catalog=AdoDotNet35Cookbook;";
private static string sqlSelect = "SELECT * FROM DataAdapterTransaction";
static void Main(string[] args)
{
object[,] o1 = {{ "1", "field 1.1", "field 2.1" },
{ "2", "field 1.2", "field 2.2" }};
InsertRecords(o1);
object[,] o2 = {{ "3", "field 1.3", "field 2.3" },
{ null, "field 1.4", "field 2.4" }};
InsertRecords(o2);
// Retrieve and output the contents of the table
SqlDataAdapter daRead = new SqlDataAdapter(sqlSelect, sqlConnectString);
DataTable dtRead = new DataTable( );
daRead.Fill(dtRead);
Console.WriteLine("---TABLE DataAdapterTransaction---");
foreach (DataRow row in dtRead.Rows)
Console.WriteLine("Id = {0}\tField1 = {1}\tField2 = {2}",
row["Id"], row["Field1"], row["Field2"]);
Console.WriteLine("\nPress any key to continue.");
Console.ReadKey( );
}
static void InsertRecords(object[,] o)
{
DataTable dt = new DataTable( );
SqlTransaction tran;
SqlConnection connection = new SqlConnection(sqlConnectString);
// Create a DataAdapter
SqlDataAdapter da = new SqlDataAdapter(sqlSelect, connection);
// Stop updating when an error is encountered for roll back.
da.ContinueUpdateOnError = false;
// Create CommandBuilder and generate updating logic.
SqlCommandBuilder cb = new SqlCommandBuilder(da);
// Create and fill a DataTable with schema and data
da.Fill(dt);
// Open the connection
connection.Open( );
// Begin a new transaction and assign it to the DataAdapter
tran = connection.BeginTransaction( );
da.SelectCommand.Transaction = tran;
// Add two rows that will succeed update
for (int i = 0; i <= o.GetUpperBound(0); i++)
{
dt.Rows.Add(new object[] { o[i, 0], o[i, 1], o[i, 2] });
Console.WriteLine(
"=> Row with [Id = {0}] added to DataTable.", o[i, 0]);
}
Console.WriteLine("=> Updating data source using DataAdapter.");
try
{
da.Update(dt);
tran.Commit( );
Console.WriteLine("\nTRANSACTION COMMIT.\n");
}
catch (Exception ex)
{
tran.Rollback( );
Console.WriteLine("\nTRANSACTION ROLLBACK.\n{0}\n", ex.Message);
}
finally
{
connection.Close( );
}
}
}
}
Okay, so what i'm after is just after the transaction commit, I want to get the (scope) identity of the the last inserted row.
My application is successful in updating three dataadapters as part of the transaction, however I am having dificulty looking at the final committed data. I can do a select of the table and see it in there, but that really isn't good enough for production code.
SC
You may just need to reselect the data.
The Books Online says that you should call a Fill again to bring the update your Dataset:
http://msdn.microsoft.com/en-us/library/33y2221y(VS.71).aspx
I generally set my Insert and Update commands so that they they return back a valid DataRow for my DataTable and control the update of the rows in the application that way.
Right so I should do:
// update datatable
da.Update(dt);
// commit updates
tran.Commit( );
// get the updated datatable
da.Fill(dt);
I assume all the identity colums will be updated.
I'll give it a go
SC
I understand you're using identity columns, but is there any natural key in the data you can use to reselect?
(that then raises the question of 'why use identities' but that's a whole other subject...)
Unfortunately no, I cannot reselect using a natural key... I'm stuck with identities... after 8 hours of head banging I contemplated adding a guid field so I could get it to work, but decided that it is against my principles to give up!
SC
This MSDN article describes how to get back identity values when calling the Update method of a DataAdapter.