I have a C# application which retrieves the required information and stores it in a array, I am using Finisar sqlite to create my database entry.
Can anybody guide me as to how I can write retrieved array values to the sqlite database. Any help will be extremely thankful.
Here is what worked for me. In my case, I had a global array and inserted it into sqlite db.
SQLiteConnection con = new SQLiteConnection(/*Your Connection String*/);
string AddFormationTop = "INSERT INTO Formation (WellID, Param1, Param2, Param3)
VALUES ((SELECT WellID FROM Wells WHERE WellName = #WellName), #Param1, #Param2, #Param3)";
SQLiteCommand cmd = new SQLiteCommand(AddFormationTop, con);
string pParam1;
double pParam2;
double pParam3;
con.Open();
// of course, your "for" case might be different.
for (int i = 1; i < GlobalVar.Formation.Length - 1; i++)
{
pParam1 = GlobalVar.Param1[i];
pParam2 = Convert.ToDouble(GlobalVar.Param2[i]);
pParam3 = Convert.ToDouble(GlobalVar.Param3[i]);
cmd.Parameters.AddWithValue("#WellName", Properties.Settings.Default.ActiveWell);
cmd.Parameters.AddWithValue("#Param1", pParam1);
cmd.Parameters.AddWithValue("#Param2", pParam2);
cmd.Parameters.AddWithValue("#Param3", pParam3);
cmd.ExecuteNonQuery();
}
con.Close();
Related
I am trying to use Arraybinding to load multiple rows into a table. The approach works for inline queries but not when done via Stored Procedure.
I am expecting that an exception is raised with inner Errors object populated with row numbers where it failed.
This is an example from Oracle site and it works perfectly fine for me. But as soon as i replace the inline query with a stored procedure, it fails with single error and doesn't contain any information for the row which failed.
https://docs.oracle.com/html/B14164_01/featOraCommand.htm#i1007888
/* Database Setup
drop table depttest;
create table depttest(deptno number(2));
*/
This is the program
using System;
using System.Data;
using Oracle.DataAccess.Client;
class ArrayBindExceptionSample
{
static void Main()
{
OracleConnection con = new OracleConnection();
con.ConnectionString = "User Id=scott;Password=tiger;Data Source=oracle;";
con.Open();
OracleCommand cmd = new OracleCommand();
// Start a transaction
OracleTransaction txn = con.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
int[] myArrayDeptNo = new int[3] { 10, 200000, 30 };
// int[] myArrayDeptNo = new int[3]{ 10,20,30};
// Set the command text on an OracleCommand object
cmd.CommandText = "insert into depttest(deptno) values (:deptno)";
cmd.Connection = con;
// Set the ArrayBindCount to indicate the number of values
cmd.ArrayBindCount = 3;
// Create a parameter for the array operations
OracleParameter prm = new OracleParameter("deptno", OracleDbType.Int32);
prm.Direction = ParameterDirection.Input;
prm.Value = myArrayDeptNo;
// Add the parameter to the parameter collection
cmd.Parameters.Add(prm);
// Execute the command
cmd.ExecuteNonQuery();
}
catch (OracleException e)
{
Console.WriteLine("OracleException {0} occured", e.Message);
if (e.Number == 24381)
for (int i = 0; i < e.Errors.Count; i++)
Console.WriteLine("Array Bind Error {0} occured at Row Number {1}",
e.Errors[i].Message, e.Errors[i].ArrayBindIndex);
txn.Commit();
}
cmd.Parameters.Clear();
cmd.CommandText = "select count(*) from depttest";
decimal rows = (decimal)cmd.ExecuteScalar();
Console.WriteLine("{0} row have been inserted", rows);
con.Close();
con.Dispose();
}
}
Replace the code with stored procedure
cmd.CommandText = "SPName";
cmd.CommandType = CommandType.StoredProcedure;
Stored Procedure
PROCEDURE trial (p_deptno IN number)
AS
BEGIN
insert into ses.depttest(deptno) values (P_deptno);
END trial;
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'm having two mysql TABLES - ORDER and ORDER_DETAILS the relationship is one order has many order_details.
After creating an order, I get the last inserted id and I need to insert order details with last inserted last order id via a for loop. But here it is showing a message
#order_id has already been defined
when having more than one order details. If it is one order detail it works.
How can I defined this order id here? Is this a wrong way? Here is my code:
private void button2_Click(object sender, EventArgs e)
{
try
{
DateTime localDate = DateTime.Now;
MydbConnection db = new MydbConnection();
MySqlConnection con = db.connection();
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "insert into orders (created) values(#localDate)";
cmd.Parameters.AddWithValue("#localDate", localDate);
cmd.Connection = con;
con.Open();
cmd.ExecuteNonQuery();
long lastId = cmd.LastInsertedId;//Last inserted id
for (int i = 0; i < listView3.Items.Count; i++)
{
cmd.CommandText = "insert into order_details (order_id,product_id,qty) values(#order_id,#product_id,#qty)";
cmd.Parameters.AddWithValue("#order_id", lastId);
cmd.Parameters.AddWithValue("#product_id", 1);
cmd.Parameters.AddWithValue("#qty", listView3.Items[i].SubItems[1]);
cmd.ExecuteNonQuery();
}
}
catch (Exception es) {
MessageBox.Show("Order not saved! "+es.Message);
}
}
Each time you call cmd.Parameters.AddWithValue you adding one more parameters. When you call it twice or more with parameter with same name duplicated parameters appears.
When your listView3.Items.Count contains at least two elements, your code will add duplicated #order_id, #product_id and #qty.
You need either to recreate your MySqlCommand cmd on each iteration, or change value of parameters when they already added.
First approach is more error-prone. Al least because you will not use other data left from previous usage (#localDate parameter you adding before loop, that otherwise will be also passed to database).
for (int i = 0; i < listView3.Items.Count; i++)
{
cmd = new MySqlCommand();
cmd.Connection = con;
cmd.CommandText = "insert into order_details (order_id,product_id,qty) values(#order_id,#product_id,#qty)";
cmd.Parameters.AddWithValue("#order_id", lastId);
cmd.Parameters.AddWithValue("#product_id", 1);
cmd.Parameters.AddWithValue("#qty", listView3.Items[i].SubItems[1]);
cmd.ExecuteNonQuery();
}
You can't keep adding the same command parameters over and over. Instead, why not re-use them:
private void button2_Click(object sender, EventArgs e)
{
try
{
DateTime localDate = DateTime.Now;
MydbConnection db = new MydbConnection();
MySqlConnection con = db.connection();
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "insert into orders (created) values(#localDate)";
cmd.Parameters.AddWithValue("#localDate", localDate);
cmd.Connection = con;
con.Open();
cmd.ExecuteNonQuery();
long lastId = cmd.LastInsertedId;//Last inserted id
cmd.CommandText = "insert into order_details (order_id,product_id,qty) values(#order_id,#product_id,#qty)";
MySqlCommandParameter orderIdParam, productIdParam, qtyParam;
for (int i = 0; i < listView3.Items.Count; i++)
{
if (i == 0)
{
orderIdParam = cmd.Parameters.AddWithValue("#order_id", lastId);
productIdParam = cmd.Parameters.AddWithValue("#product_id", 1);
qtyParam = cmd.Parameters.AddWithValue("#qty", listView3.Items[i].SubItems[1]);
}
else
{
orderIdParam.Value = lastId;
productIdParam.Value = 1;
qtyParam.Value = listView3.Items[i].SubItems[1];
}
cmd.ExecuteNonQuery();
}
}
catch (Exception es) {
MessageBox.Show("Order not saved! "+es.Message);
}
}
Note: I haven't actually tested this code and probably have the wrong types and member names for MySqlCommandParameter and MySqlCommandParameter.Value but you should still get the idea.
It would probably be better coding practice to Add the parameters first (before entering the loop) and not have the if block in the loop instead of using AddWithValue for the first loop iteration. You could also think about Clear-ing the parameter collection on the command and calling AddWithValue every iteration. Ultimately, I think it is best to re-use the parameters, though - certainly preferable to creating a new instance of MySqlCommand every iteration - there might be thousands of iterations!
Firstly, as hinted in the comments, you need a way to remove the parameters added in the previous iteration of the loop:
cmd.Parameters.Clear();
placed after cmd.ExecuteNonQuery() will do that for you. But beware! The SQL connection, and the SQL command, .NET base types implement IDisposable, and you should despose of them properly when you're done with them to avoid things like connection pool blocking. I've recently had to rescue an old project from poorly managed disposables and a) it was a pain but b) the result was a much faster, more reliable app. You might want to look in to that when you've solved your current problem.
I need to change my field QB_STATUS from value R to value C. I am doing this in a loop because i cannot "requery" the table as data may have changed.
I have built a list of entries to update. The code does not error and iterates through 5 times (correct based on my idInvoices list) but the field does not get updated.
for (int i = 0; i < idInvoices.Count; i++)
{
// following command will update one row as ID_Invoice is primary key.
// ID_Invoice taken from list previously built in ReadDataToNAVArray
SqlCommand cmd = new SqlCommand("UPDATE tblINVOICES SET QB_STATUS=#Status WHERE ID_INVOICE = #IDInvoice", myConnection);
cmd.Parameters.Add("#Status", "C");
cmd.Parameters.Add("#IDInvoice", idInvoices[i]);
cmd.Dispose();
}
First, you have to execute your query: ExecuteNonQuery; second - do not create command, parameters etc within the loop, just assign values and execute:
// Make SQL readable
String sql =
#"UPDATE tblINVOICES
SET QB_STATUS = #Status
WHERE ID_INVOICE = #IDInvoice";
// wrap IDisposable into "using"
// do not recreate command in the loop - create it once
using (SqlCommand cmd = new SqlCommand(sql, myConnection)) {
cmd.Parameters.Add("#Status", SqlDbType.VarChar); //TODO: check types, please
cmd.Parameters.Add("#IDInvoice", SqlDbType.Decimal); //TODO: check types, please
// Assign parameters with their values and execute
for (int i = 0; i < idInvoices.Count; i++) {
cmd.Parameters["#Status"].Value = "C";
cmd.Parameters["#IDInvoice"].Value = idInvoices[i];
cmd.ExecuteNonQuery();
}
}
You are missing the ExecuteNonQuery in your command.
for (int i = 0; i < idInvoices.Count; i++)
{
SqlCommand cmd = new SqlCommand("UPDATE tblINVOICES SET QB_STATUS=#Status WHERE ID_INVOICE = #IDInvoice", myConnection);
cmd.Parameters.Add("#Status", "C");
cmd.Parameters.Add("#IDInvoice", idInvoices[i]);
cmd.ExecuteNonQuery();
cmd.Dispose();
}
I think you're missing cmd.ExecuteNonQuery();.
An example for a different way of using sql commands:
SqlConnection addConn = new SqlConnection();
addConn.ConnectionString = Properties.Settings.Default.yourDataBaseConnection;
addConn.Open();
SqlCommand addComm = new SqlCommand();
addComm.Connection = addConn;
addComm.CommandText = "sql command";
addComm.ExecuteNonQuery();
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...