The function of application is to select some values from one database (PSQL) and insert it into another database (SQLite). But code below does not work, it stops at executing line and shows no error, but last forever (also if I use SELECT TOP 1 ...).
//... odbc conection to DSN, this works fine
odbc.dbsqlite.Open();
odbc.dbpsql.Open();
//sql command
OdbcCommand comsqlite = odbc.dbsqlite.CreateCommand();
OdbcCommand compsql = odbc.dbpsql.CreateCommand();
//SQL for select ... this works
compsql.CommandText = "SELECT DISTINCT ..."
compsql.Parameters.AddWithValue("#sifra", "VP");
...
// from here is problem
try
{
OdbcDataReader dbReader = compsql.ExecuteReader();
OdbcTransaction transaction = odbc.dbsqlite.BeginTransaction();
var ordinal = new
{
cenik = dbReader.GetOrdinal("sifra"),
ident = dbReader.GetOrdinal("ident"),
klasi = dbReader.GetOrdinal("klasi"),
cena = dbReader.GetOrdinal("cena"),
eankoda = dbReader.GetOrdinal("eankoda"),
};
int count = 0;
while (dbReader.Read())
{
//here single variable gets results
var cena = Convert.ToDouble(dbReader.GetDouble(ordinal.cena));
var ident = Convert.ToString(dbReader.GetString(ordinal.ident));
var cenik = Convert.ToString(dbReader.GetString(ordinal.cenik));
var klasi = Convert.ToString(dbReader.GetString(ordinal.klasi));
var eanko = Convert.ToString(dbReader.GetString(ordinal.eankoda));
comsqlite.CommandText = "INSERT INTO ARTIKLI (KLASI, CENA, BARKODA, CENIK, IDENT) VALUES (?,?,?,?,?);";
comsqlite.Parameters.AddWithValue("#KLASI", klasi);
comsqlite.Parameters.AddWithValue("#CENA", cena);
comsqlite.Parameters.AddWithValue("#BARKODA", eanko);
comsqlite.Parameters.AddWithValue("#CENIK", cenik);
comsqlite.Parameters.AddWithValue("#IDENT", ident);
if (count % 1000 == 0)
{
transaction.Commit();
transaction.Dispose();
**comsqlite.ExecuteNonQuery(); //here it stops and give no results**
transaction = odbc.dbsqlite.BeginTransaction();
}
count++;
}
comsqlite.Dispose();
odbc.dbsqlite.Close();
transaction.Commit();
transaction.Dispose();
dbReader.Close();
compsql.Dispose();
odbc.dbpsql.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: "+ e);
throw;
}
I am not sure what your CommandText looks like at this point, but you should try to set some single quotation marks around the values being strings/characters in your database.
comsqlite.CommandText = "INSERT INTO ARTIKLI (KLASI, CENA, BARKODA, CENIK, IDENT) VALUES ('?','?','?','?','?');";
Related
How to implement counter, so that it commit multiple queries, for example every 1000 "queries". Problem is that with or without transaction query is executed by "ExecuteNonQuery()" and it execute one by one, not as I whant e.g. every 1000?
odbc.dbsqlite.Open();
odbc.dbkopito.Open();
OdbcCommand comlite = odbc.dbsqlite.CreateCommand();
OdbcCommand comkopit = odbc.dbkopito.CreateCommand();
OdbcTransaction transaction = null;
comkopit.CommandText =
"SELECT DISTINCT ... "
#region TRY
try
{
OdbcDataReader dbKopitReader = comkopit.ExecuteReader();
var ordinal = new
{
cenik = dbKopitReader.GetOrdinal("sifra"),
ident = dbKopitReader.GetOrdinal("ident"),
klasifikacija = dbKopitReader.GetOrdinal("klasifikacija"),
cena = dbKopitReader.GetOrdinal("cena"),
eankoda = dbKopitReader.GetOrdinal("eankoda"),
};
int stevec = 0;
while (dbKopitReader.Read())
{
var cena = Convert.ToDouble(dbKopitReader.GetDouble(ordinal.cena));
var ident = Convert.ToString(dbKopitReader.GetString(ordinal.ident));
var cenik = Convert.ToString(dbKopitReader.GetString(ordinal.cenik));
var klasi = Convert.ToString(dbKopitReader.GetString(ordinal.klasifikacija));
var eanko = Convert.ToString(dbKopitReader.GetString(ordinal.eankoda));
using (var cmd = odbc.dbsqlite.CreateCommand() )
{
try
{
cmd.CommandText = "INSERT OR REPLACE INTO ARTIKLI (KLASIFIKACIJA, CENA, BARKODA, CENIK, IDENT) " +
"VALUES (?,?,?,?,?);";
cmd.Parameters.AddWithValue("#KLASIFIKACIJA", klasi);
cmd.Parameters.AddWithValue("#CENA", cena);
cmd.Parameters.AddWithValue("#BARKODA", eanko);
cmd.Parameters.AddWithValue("#CENIK", cenik);
cmd.Parameters.AddWithValue("#IDENT", ident);
cmd.ExecuteNonQuery();
if (stevec % 1000 == 0)
{
transaction.Commit();
transaction = odbc.dbsqlite.BeginTransaction();
cmd.Transaction = transaction;
}
stevec++;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
try
{
transaction.Rollback();
}
catch
{
Console.WriteLine("Transakcija ni aktivna");
}
}
}
}
comlite.Dispose();
odbc.dbsqlite.Close();
dbKopitReader.Close();
comkopit.Dispose();
odbc.dbkopito.Close();
Transaction is not initiated at first iteration (should get null exception).
Transaction is not assigned to command.
You creating transaction and assigning it to command every 1000th, but next 999 commands is created without transactions.
You committing transaction on very first iteration.
Here is example how your code should look like:
var transaction = odbc.dbsqlite.BeginTransaction();
int count = 0;
while(read)
{
count++;
if(count % 1000 == 0)
{
transaction.Commit();
transaction = odbc.dbsqlite.BeginTransaction();
}
//I imagine this CreateCommand() is assigning connection...
using(var cmd = odbc.dbsqlite.CreateCommand())
{
cmd.CommandText = "INSERT...";
//Params...
cmd.Transaction = transaction;
cmd.ExecuteNonQuery();
}
}
As the server requires a connection for each database, the answers I've found in SO don't work at all.
For some tables I have to make some calculations before copying the rows, but some I can copy whole table. And finally it's an automation in my program that I've wrote.
Oldcn is the connection to old database, Newcn for the new database.
For the tables that I can copy whole I wrote this procedure below.
Is there a better an short way to do this job? (It works on background)
private string[] CopyTva(MySqlConnection Oldcn, MySqlConnection Newcn, string[] res, DoWorkEventArgs we,string msg)
{
int counter = int.Parse(res[1]);
MySqlCommand cmd = new MySqlCommand("SELECT * FROM tvaval", Oldcn);
MySqlCommand cmd1 = new MySqlCommand("INSERT INTO tvaval (id,tvavalue,cr_user,cr_date,up_user,up_date) VALUES (#id,#tvavalue,#cr_user,#cr_date,#up_user,#up_date)", Newcn);
MySqlDataReader rd = null;
try
{
rd = cmd.ExecuteReader();
while (rd.Read())
{
cmd1.Parameters.AddWithValue("#id", rd["id"].ToString());
//bla bla same as above
try
{
cmd1.ExecuteNonQuery();
}
catch (MySqlException e)
{
rd.Dispose();
res[2] = "Erreur:TVA " + e.Message.ToString();
return res;
}
++counter;
bgw.ReportProgress((counter * 100) / DbTotalRow,msg);
cmd1.Parameters.Clear();
}
rd.Dispose();
}
catch (MySqlException e)
{
res[2] = "Erreur:TVA " + e.Message.ToString();
return res;
}
res[0] = "1";res[1] = counter.ToString();res[2] = "";
return res;
}
MySQL doesn't require a separate connection for each database. A connection has a default database, but you're allowed to specify the database name explicitly before the table name, and this will override the default. So you can do this with a single query:
INSERT INTO newdb.tvaval
SELECT * FROM olddb.tvaval
I have a datagridview which is created by various action and user's manipulation of data. I want to insert all the data of the gridview to the database at once, I know I could try a code similar to this:
private void btnSaveProducts_Click(object sender, EventArgs e)
{
SqlConnection connection = DBConnectivity.getConnection();
if (connection != null)
{
try
{
for (int i = 0; i < dGvProducts.Rows.Count; i++)
{
string query = "INSERT INTO product (productName) " + "VALUES (#productName)";
SqlCommand command = DBConnectivity.getCommandForQuery(query, connection);
int result = command.ExecuteNonQuery();
Console.WriteLine(result + "");
}
// string query = "Insert into units(name,packing)values('" + txtNameUnit.Text + "' , '" + txtPackingUnit.Text + "')";
// SqlCommand command = DBConnectivity.getCommandForQuery(query, connection);
// int result = command.ExecuteNonQuery();
// Console.WriteLine(result + "");
}
catch (Exception ex)
{
}
finally
{
connection.Close();
}
}
}
As is, the code tries to execute a parameterized query but never assigns a value to the parameter. Even if you do, you never extract the cell values.
The code should look like this:
var query = "INSERT INTO product (productName) VALUES (#productName)";
using var(connection = DBConnectivity.getConnection())
using(var command = new SqlCommand(query, connection))
{
var productParam=command.Parameters.Add("#productName",SqlDbType.NVarChar,50);
connection.Open();
for (int i = 0; i < dGvProducts.Rows.Count; i++)
{
var productName=dGvProducts.Rows[i].Cells[somecolumn].Value;
productParam.Value=productName;
int result = command.ExecuteNonQuery();
Console.WriteLine(result);
}
}
My code looks like this:
var settings = ConfigurationManager.ConnectionStrings["InsurableRiskDB"];
string server = ConfigurationManager.AppSettings["Server"];
string cs = String.Format(ConfigurationManager.AppSettings[settings.ProviderName], ConfigurationManager.AppSettings[server]);
SqlConnection connection = new SqlConnection(cs);
string PolicyKeys = "";
for (int i = 0; i < keys.Count(); i++)
{
if (i == keys.Count() - 1)
PolicyKeys += keys[i] ;
else
PolicyKeys += keys[i] + ", ";
}
//have to change the code to pull the user's NBK.
string user = "'DATALOAD'";
const string updateQuery = #"UPDATE [InsurableRisk].[dbo].[Policy]
SET [InsuranceCarrierKey] = #ToKey
,[AuditUser] = #User
,[AuditDate] = SYSDATETIME()
WHERE PolicyKey in (#PolicyKeys) and InsuranceCarrierKey = #FromKey";
using (connection)
{
using (SqlCommand dataCommand = new SqlCommand(updateQuery, connection))
{
dataCommand.Parameters.AddWithValue("#ToKey", toKey);
dataCommand.Parameters.AddWithValue("#User", user);
dataCommand.Parameters.AddWithValue("#PolicyKeys", PolicyKeys);
dataCommand.Parameters.AddWithValue("#FromKey", fromKey);
connection.Open();
dataCommand.ExecuteNonQuery();
connection.Close();
}
}
res = true;
}
catch (Exception ex)
{
MessageBox.Show("There is an error while try in save the changes " + ex.Message, "Error Message", MessageBoxButtons.OKCancel);
res = false;
}
return res;
Now, when i run this code, it says query is unable to execute. It throws and exception stating, it is unable to convert NVarchar to int for variable #PolicyKeys
Any suggestions as to what i am missing in this code?
Typically, in SQL you'd write an IN statement like this:
WHERE SomeColumn IN ('A', 'B', 'C')
What you're doing is the equivalent of this in SQL (which won't work):
WHERE SomeColumn IN ('A, B, C')
Change your SQL statement accordingly: (modified from this answer)
WHERE PolicyKey in ({0})
And then add your parameters in a loop, like this:
var parameters = new string[keys.Count()];
for (int i = 0; i < keys.Count(); i++)
{
parameters[i] = string.Format("#Key{0}", i);
cmd.Parameters.AddWithValue(parameters[i], keys[i]);
}
cmd.CommandText = string.Format(updateQuery, string.Join(", ", parameters));
This is s for loop and it will go to the times and will put the time column as true. This works for the first time, but when the time increases by 0.5, it stays false. The for loop is working as i tried a MessageBox.Show("" + Time1 + ""); inside the for loop.
for (double Time = time_began_5; Time < time_finished_5; Time = Time + 0.5)
{
string Time1 = Time.ToString("0.00");
try
{
SqlConnection cn = new SqlConnection("Data Source=.\\SqlExpress;Initial Catalog=AllensCroft;Integrated Security=True;MultipleActiveResultSets=True;Application Name=EntityFramework;");
cn.Open();
SqlCommand Command = new SqlCommand("INSERT INTO Slots ([Date],[RoomID],[" + Time1 + "]) Values (#date,#room,1)", cn);
Command.Parameters.AddWithValue("date", date);
Command.Parameters.AddWithValue("room", rooms_combo.SelectedValue);
Command.ExecuteNonQuery();
try
{
cn.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Here is what the database looks like, the first true field works, but when it loops to another time, it remains false, I think it may be due to the fact that if I have an existing row with that date (date is primary key), i cannot update that row, so i might need to have an IF the row exists, update, else create a new row.
Try this, you don't have to open connection in each loop, create your sql statement first looping through each value and then do insert using one statement
private string CreateInsertStatement(double time_began_5, double time_finished_5)
{
string sql = "INSERT INTO Slots ([Date],[RoomID],";
string valuesql = " Values (#date,#room,";
for (double Time = time_began_5; Time < time_finished_5; Time = Time + 0.5)
{
string Time1 = Time.ToString("0.00");
sql+ = "[" + Time1 + "],";
valuesql+ = "1,";
}
sql = sql.TrimEnd(',') + ") ";
valuesql = valuesql.TrimEnd(',') + ") ";
return sql + valuesql;
}
private string CreateUpdateStatement(double time_began_5, double time_finished_5)
{
string sql = "UPDATE Slots SET ";
string wheresql = " WHERE [Date] = #date AND [RoomID] = #room";
for (double Time = time_began_5; Time < time_finished_5; Time = Time + 0.5)
{
string Time1 = Time.ToString("0.00");
sql+ = "[" + Time1 + "] = 1,";
}
sql = sql.TrimEnd(',');
return sql + wheresql;
}
Then in you actual insert code:
try
{
SqlConnection cn = new SqlConnection("Data Source=.\\SqlExpress;Initial Catalog=AllensCroft;Integrated Security=True;MultipleActiveResultSets=True;Application Name=EntityFramework;");
cn.Open();
SqlCommand Command;
//check if row exists
Command = new SqlCommand("select count(*) from Slots WHERE [Date] = #date AND [RoomID] = #room", cn);
Command.Parameters.AddWithValue("date", date);
Command.Parameters.AddWithValue("room", rooms_combo.SelectedValue);
var cnt = Command.ExecuteScalar();
if(cnt!=null)
{
string sqlstr = ""
if(Int32.Parse(cnt.ToString()) > 0)
{
sqlstr = CreateUpdateStatement(time_began_5,time_finished_5);
}
else if(Int32.Parse(cnt.ToString()) == 0)
{
sqlstr = CreateInsertStatement(time_began_5,time_finished_5);
}
Command = new SqlCommand(sqlstr, cn);
Command.Parameters.AddWithValue("date", date);
Command.Parameters.AddWithValue("room", rooms_combo.SelectedValue);
Command.ExecuteNonQuery();
}
try
{
cn.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
You are doing an insert.
In every loop you insert a new row and set the value true only for the column which name is equal to the current value of the variable Time1.
Not having a value for the other columns they probably default to false. (bit columns I suppose)
If you want a default to true for every column perhaps it is better to change the database schema adding the default for every time column, otherwise you need a long list of parameters
EDIT: If your logic dictates that you need only one row per date and set every time column to true if you enter the situation above then you can move this logic in the database using a stored procedure:
CREATE PROCEDURE InsertOrUpdateSlotFromCode(#dt smalldatetime, #roomID int)
AS
BEGIN
DECLARE #cnt INT
SELECT #cnt = COUNT(*) from Slots WHERE [Date] = #dt
if #cnt = 0
INSERT INTO Slots ([Date],[RoomID], <here all the time fields> VALUES (#dt, #roomID, 1, ....)
else
UPDATE Slots SET [09.00] = 1, ..... WHERE [Date] = #dt
End
END
then your code call the sp
using(SqlConnection cn = new SqlConnection(.........))
{
cn.Open();
SqlCommand Command = new SqlCommand("InsertOrUpdateSlotFromCode", cn);
Command.CommandType = CommandType.StoredProcedure;
Command.Parameters.AddWithValue("date", date);
Command.Parameters.AddWithValue("room", rooms_combo.SelectedValue);
Command.ExecuteNonQuery();
}
Of course now you can completely get rid of the loop