This program was already written and I need to add to it an update SQL statement to update another table based on #IN. After declaring the SQL command how do I get it to excute, can I use the same SQLConnection as other sql command? WHat this program does is it parses in a file to a list called individuals and from that I just want to update the fields in SQL. The first SQL was already written in an seems to execute correctly now I need to do the UpdtHasInv SQL and actually get the code to perform the update is where I need help.
Heres what I have so far:
static void InsertCustomData(Collection<Individuals> individuals)
{
#region
string insertsql = "";
insertsql = #"Insert into IND (IND_ID, ITEM_NAME, INDL_ITEM_VALUE, XPTIM)
select IND_ID, '{0}' as Item, '{1}' as val, (current timestamp - curtime)"
FROM IND
where IN = #IN";
// this is SQL I added for update
**UpdtHasInv = #"UPDATE Ind
SET HAS_I = -1
WHERE IN = #IN";**
#endregion
using (DB2Connection conn = DB2Helper.getConnection())
{
DB2Command cmd = conn.CreateCommand();
cmd.CommandTimeout = 600;
cmd.Parameters.Add("#IN", "");
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
foreach (Individuals individual in individuals)
{
cmd.Parameters["#IN"].Value = individual.In;
foreach (CustomData customData in individual.CustomData)
{
cmd.CommandText = string.Format(insertIndsql, customData.Data.Key, customData.Data.Value);
Could I just write : 'cmd.CommandText = UpdtIsInv;' after these lines:
foreach (Individuals individual in individuals)
{
cmd.Parameters["#IN"].Value = individual.in
You could simply append your UPDATE after the INSERT using a semicolon.
insertIndsql = #"
INSERT INTO IND (IND_ID, ITEM_NAME, INDL_ITEM_VALUE, XPTIMESTAMP)
SELECT INDIVIDUAL_ID, '{0}' as Item, '{1}' as val, (current timestamp - curtime)
FROM IND
WHERE TIN = #TIN;
UPDATE DB2INST1.Individual
SET HAS_INVESTMENT = -1
WHERE TIN = #TIN;";
When executed, both statements will be executed as part of the same command.
Related
I have been working on a personal project for the company I work for to control stock levels in order to practice my c#.
I want my application to search through tblJuiceStock, find a matching FlavourID to what the user is inputting and update the stock of that record through an UPDATE SET query.
public void InsertJuiceStockWithCheck()
{
using (OleDbConnection conn = new OleDbConnection())
{
conn.ConnectionString = ConnectionString;
conn.Open();
string tblJuiceStockCheck = "SELECT FlavourID, Quantity FROM tblJuiceStock";
OleDbCommand cmdCheck = new OleDbCommand(tblJuiceStockCheck, conn);
OleDbDataAdapter daCheck = new OleDbDataAdapter(cmdCheck);
DataTable dtCheck = new DataTable();
daCheck.Fill(dtCheck);
foreach (DataRow row in dtCheck.Rows)
{
if ((int)row["FlavourID"] == fID)
{
int currentQty = (int)row["Quantity"];
int updatedQty = currentQty + qty;
string tblJuiceStockExisting = #"UPDATE tblJuiceStock
SET Quantity = #newquantity
WHERE FlavourID = #flavourID";
OleDbCommand cmdJuiceStockExisting = new OleDbCommand(tblJuiceStockExisting, conn);
cmdJuiceStockExisting.Parameters.AddWithValue("#flavourID", fID);
cmdJuiceStockExisting.Parameters.AddWithValue("#newquantity", updatedQty);
cmdJuiceStockExisting.ExecuteNonQuery();
matchFound = true;
break;
}
}
if (!matchFound)
{
string tblJuiceStockNew = "INSERT INTO tblJuiceStock (FlavourID, Quantity, MinStockPOS) VALUES (#fID, #quantity, #minstock)";
OleDbCommand cmdJuiceStockNew = new OleDbCommand(tblJuiceStockNew, conn);
cmdJuiceStockNew.Parameters.AddWithValue("#fID", fID);
cmdJuiceStockNew.Parameters.AddWithValue("#quantity", qty);
cmdJuiceStockNew.Parameters.AddWithValue("#minstock", amt);
cmdJuiceStockNew.ExecuteNonQuery();
}
}
}
Please note: this query works fine in Access when I replace parameters with the same values. Also, using breakpoints I identified that the parameters have the correct values set to them, the variables assigned to them are obtained within another method, all methods are called in the submit button event.
However, the Quantity value in TblJuiceStock remains the same.
My tblJuiceStock table
After some time of messing about the answer was simple.
OLEDB does work with named parameters but you have to declare them, if you don't declare them they use the parameters positioning to match them up.
My problem was that in my query string I had #newquantity first and #flavourID second, whereas when adding my parameters I added #flavourID first and #newquantity second.
I want to select several values from database (ODBC datasource). The table is this simple:
| name | value |
+------+-------+
| abcd | 12345 |
Say I want to select values where name is name1, name2 and name3:
SELECT name, value FROM my_table WHERE name="name1" OR name="name2" OR name="name3"
Now I could generate this command:
public string MakeCommand(List<string> names) {
string command = "SELECT name, value FROM my_table WHERE ";
bool first = true;
foreach(string name in names) {
if(first)
first = false;
else
command+=" OR ";
command+="name=\""+name+"\"";
}
}
I hope it's not necessary to emphasize that this would be very bad way to access the database.
So how can I make this a parametrized ODBC command, as described here?
Well, the simplest solution is probably to concatenate a parameter to the sql for each value in your list, and then add this value as a parameter to the OdbcCommand.
using(var command = new OdbcCommand())
{
string sql = "SELECT name, value FROM my_table WHERE name IN(";
for(int i=0; i < names.Count; i++) {
sql = $"{sql} #{i},";
command.Parameters.Add($"#{i}", OdbcType.VarChar).Value = names[i];
}
command.CommandText = sql.TrimEnd(",") +");";
command.Connection = con;
// fill a data set or execute a data reader here....
}
There is no elegant solution to this problem. You can use the IN clause but, still you need to build the parameters one by one. So instead of returning a string you can return the OdbcCommand prepared with all the parameters required by your list of names. Just need to add the connection and execute (or pass also the connection and prepare everything here)
public OdbcCommand MakeCommand(List<string> names, OdbcConnection con) {
List<OdbcParameter> parameters = new List<OdbcParameter>();
List<string> placeholders = new List<string>();
foreach(string name in names) {
OdbcParameter p = new OdbcParameter("?", OdbcType.NVarChar);
p.Value = name;
parameters.Add(p);
placeholders.Add("?")
}
string command = "SELECT name, value FROM my_table WHERE name IN(";
command = command + string.Join(",", placeholders.ToArray()) + ")";
OdbcCommand cmd = new OdbcCommand();
cmd.CommandText = command;
cmd.Connection = con;
cmd.Parameters.AddRange(parameters.ToArray());
return cmd;
}
If you still have problems, then it could be something linked to the parameters DataType. NVarChar, VarChar, Text, String. Some db could react differently to this type. What database are you testing this code against?
I have tried to give multiple insert or update in single query like
OleDbCommand command = new OleDbCommand("INSERT INTO Employee (Id,
Name, Address, Salary) VALUES (2001, 'name1', 'address1',
100000);UPDATE Employee SET Salary = 2000000 WHERE Id = 2001;");
This executes successfully.
But I don't want multiple sql queries in single execution. Is there anything like any property or something like that in C# which can be used to restrict to only one query.
I want to restrict it to single sql query in single execution.
Thanks.
Try something like this
Create a stringbuilder of values
StringBuilder sb = new StringBuilder();
string sep = "";
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
sb.AppendFormat("value1","value2" etc);
}
string insertthis = sb.ToString();
Then insert to sql
using (OleDbCommand cmd = new OleDbCommand("INSERT INTO Employee (ItemName) VALUES (#ins)", con))
{
cmd.Parameters.AddWithValue("#ins", insertthis );
cmd.ExecuteNonQuery();
}
MessageBox.Show("Data added");
Update also works like same as insert
Ref
I searched on the net something but nothing really helped me. I want to update, with a list of article, a database, but the way that I've found is really slow.
This is my code:
List<Article> costs = GetIdCosts(); //here there are 70.000 articles
conn = new OleDbConnection(string.Format(MDB_CONNECTION_STRING, PATH, PSW));
conn.Open();
transaction = conn.BeginTransaction();
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = transaction;
cmd.CommandText = "UPDATE TABLE_RO SET TABLE_RO.COST = ? WHERE TABLE_RO.ID = ?;";
for (int i = 0; i < costs.Count; i++)
{
double cost = costs[i].Cost;
int id = costs[i].Id;
cmd.Parameters.AddWithValue("data", cost);
cmd.Parameters.AddWithValue("id", id);
if (cmd.ExecuteNonQuery() != 1) throw new Exception();
}
}
transaction.Commit();
But this way take a lot of minutes something like 10 minutes or more. There are another way to speed up this updating ? Thanks.
Try modifying your code to this:
List<Article> costs = GetIdCosts(); //here there are 70.000 articles
// Setup and open the database connection
conn = new OleDbConnection(string.Format(MDB_CONNECTION_STRING, PATH, PSW));
conn.Open();
// Setup a command
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = "UPDATE TABLE_RO SET TABLE_RO.COST = ? WHERE TABLE_RO.ID = ?;";
// Setup the paramaters and prepare the command to be executed
cmd.Parameters.Add("?", OleDbType.Currency, 255);
cmd.Parameters.Add("?", OleDbType.Integer, 8); // Assuming you ID is never longer than 8 digits
cmd.Prepare();
OleDbTransaction transaction = conn.BeginTransaction();
cmd.Transaction = transaction;
// Start the loop
for (int i = 0; i < costs.Count; i++)
{
cmd.Parameters[0].Value = costs[i].Cost;
cmd.Parameters[1].Value = costs[i].Id;
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
// handle any exception here
}
}
transaction.Commit();
conn.Close();
The cmd.Prepare method will speed things up since it creates a compiled version of the command on the data source.
Small change option:
Using StringBuilder and string.Format construct one big command text.
var sb = new StringBuilder();
for(....){
sb.AppendLine(string.Format("UPDATE TABLE_RO SET TABLE_RO.COST = '{0}' WHERE TABLE_RO.ID = '{1}';",cost, id));
}
Even faster option:
As in first example construct a sql but this time make it look (in result) like:
-- declaring table variable
declare table #data (id int primary key, cost decimal(10,8))
-- insert union selected variables into the table
insert into #data
select 1121 as id, 10.23 as cost
union select 1122 as id, 58.43 as cost
union select ...
-- update TABLE_RO using update join syntax where inner join data
-- and copy value from column in #data to column in TABLE_RO
update dest
set dest.cost = source.cost
from TABLE_RO dest
inner join #data source on dest.id = source.id
This is the fastest you can get without using bulk inserts.
Performing mass-updates with Ado.net and OleDb is painfully slow. If possible, you could consider performing the update via DAO. Just add the reference to the DAO-Library (COM-Object) and use something like the following code (caution -> untested):
// Import Reference to "Microsoft DAO 3.6 Object Library" (COM)
string TargetDBPath = "insert Path to .mdb file here";
DAO.DBEngine dbEngine = new DAO.DBEngine();
DAO.Database daodb = dbEngine.OpenDatabase(TargetDBPath, false, false, "MS Access;pwd="+"insert your db password here (if you have any)");
DAO.Recordset rs = daodb.OpenRecordset("insert target Table name here", DAO.RecordsetTypeEnum.dbOpenDynaset);
if (rs.RecordCount > 0)
{
rs.MoveFirst();
while (!rs.EOF)
{
// Load id of row
int rowid = rs.Fields["Id"].Value;
// Iterate List to find entry with matching ID
for (int i = 0; i < costs.Count; i++)
{
double cost = costs[i].Cost;
int id = costs[i].Id;
if (rowid == id)
{
// Save changed values
rs.Edit();
rs.Fields["Id"].Value = cost;
rs.Update();
}
}
rs.MoveNext();
}
}
rs.Close();
Note the fact that we are doing a full table scan here. But, unless the total number of records in the table is many orders of magnitude bigger than the number of updated records, it should still outperform the Ado.net approach significantly...
//the #Question column name needs to change according to the checkbox. For example Checkbox1 - Question1
SqlConnection con = new SqlConnection(...);
String sql = "UPDATE INQUIRY2 set #Question = #str WHERE email = #email AND base = #base;";
SqlCommand cmd = new SqlCommand(sql, con);
con.Open();
//checkbox2 - question 2
//if (CheckBox3.Checked == true)
//{
// str = str + CheckBox3 + 'x';
//}
DataTable theDataTable = null;
// Verify that dt is actually in session before trying to get it
if(Session["dt"] != null)
{
theDataTable = Session["dt"] as DataTable;
}
//Verify that the data table is not null
if(theDataTable != null)
{
email = theDataTable.Rows[0]["email"].ToString();
base1 = theDataTable.Rows[0]["base"].ToString();
}
//checkbox1 - question 1
if (CheckBox9.Checked == true)
{
str = str + CheckBox9.Text + 'x';
strQuestOne = theDataTable.Columns["Question1"].ToString();
}
cmd.Parameters.AddWithValue("#email", email);
cmd.Parameters.AddWithValue("#str", str);
cmd.Parameters.AddWithValue("#Question", strQuestOne);
cmd.Parameters.AddWithValue("#base", base1);
cmd.ExecuteNonQuery();
con.Close();
You are using a parameter for a column name. Database objects (columns names, tables, stored procedures or any other objects) cannot be passed as parameters. Only actual values for columns or variables can be parameters. You need to build your SQL statement dynamically in this case:
String sql ="UPDATE INQUIRY2 set " + strQuestOne + "= #str WHERE email = ...
But now you should be carefull because you code is at risk of SQL injection attack.
Your SQL uses #param type in the string.
If you are looking to execute a stored procedure of some sort to negate most sql injection attacks on a website you might want to consider calling a stored procedure and adding SqlCommand.Parameter to the SqlCommand.Parameters Collection.
Otherwise if you want to just execute the sql you should do
string sql = String.Format("UPDATE TABLE set COLUMN = {0} where OTHERCOLUMN = {1}", varValue, varWhere);