Long Query from OracleDB - c#

I have created a query to oracle db
Dictionary<decimal, decimal> Dict = new Dictionary<decimal, decimal>();
string strSelectIdWork = "SELECT COLUMN FROM my_tb WHERE ROW='" + Row + "'";
dataAdapter.Fill(ds, "my_tb");
foreach (DataRow row in ds.Tables["my_tb"].Rows)
{
foreach (DataColumn column in ds.Tables["my_tb"].Columns)
{
Dict.Add(Dict.Count + 1, Convert.ToDecimal(row[column]));
}
}
foreach (decimal someVar in Dict.Values)
{
OleDbCommand command = myAccessConn.CreateCommand();
OleDbTransaction trans = myAccessConn.BeginTransaction();
command.Transaction = trans;
command.CommandText = "SELECT COLUMN FROM my_tb2 WHERE ROW='" + someVar + "'";
command.ExecuteNonQuery();
nb = Convert.ToString(command.ExecuteScalar());
comboBox2.Items.Add(nb;
trans.Commit();
}
It's working, but it takes a long time to execute and I have many queries in my function.
How can I change the code to reduce the time of the request?

I'm not too sure what you are trying to achieve, but do you realize that you are making countless connections to the database here?...
foreach (decimal someVar in Dict.Values)
{
OleDbCommand command = myAccessConn.CreateCommand();
OleDbTransaction trans = myAccessConn.BeginTransaction();
command.Transaction = trans;
command.CommandText = "SELECT COLUMN FROM my_tb2 WHERE ROW='" + someVar + "'";
command.ExecuteNonQuery();
nb = Convert.ToString(command.ExecuteScalar());
comboBox2.Items.Add(nb;
trans.Commit();
}
Whatever the total rows returned from this query...
"SELECT COLUMN FROM my_tb WHERE ROW='" + Row + "'"
will be equivalent to the total of database connections you will be opening...not to mentioned the total amount of transactions you will open as well. Do you really need to run a transaction for this select query?
Why don't you retrieve all the dictionary values into an array...
var values = Dict.Values.ToArray();
then join the values into a CSV string....
var #param = string.Join(",", values);
and pass this #params string to an IN clause
command.CommandText = "SELECT COLUMN FROM my_tb2 WHERE ROW IN(" + #param + ")";
var reader = command.ExecuteReader();
while(reader.Read())
{
comboBox2.Items.Add(reader["COLUMN"].ToString());
}
I'm omitting some details for clarity but if you need some clarifications, let me know

You really need to be using Bind Variables in these kind of situations. Oracle will parse each occurance of your query as a whole new query, which will slow things down considerably. I'm not a developer so I can't tell you how to apply this to C#, but you should start by reading this helpful article on the topic:
http://www.akadia.com/services/ora_bind_variables.html

Related

Bulk Update in SQL Server from C#

I have to update multiple records in SQL Server table from C#. Below are the steps I have to follow and below is the code.
The code is working but the process is taking much longer than expected.
I need a quick way to update 10000 records, not sure whether Bulk Copy would work for Update.
I have seen the other answers which has Bulk insert to temp and then update..But that update has a single statement and here I need to update the records in DB based on Excel data and for this I have to loop each excel record.So how can I achieve faster update.
1) Read the Excel Data and copied the data into a data table
string strDirectory = string. Empty;
strDirectory = System.IO.Directory.GetCurrentDirectory() + "\\" + "Filename.xlsx";
string Connection String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source = " + strDirectory + "; Extended Properties = \"Excel 12.0;HDR=YES;IMEX=1\"";
using (OleDbConnection conn = new OleDbConnection(Connection String))
{
conn.Open();
DataTable schemaTable = conn.GetOleDbSchemaTableOleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
DataRow schemaRow = schemaTable. Rows[0];
string sheet = schemaRow["TABLE_NAME"].ToString();
string query = "SELECT * FROM [" + sheet + "]";
OleDbDataAdapter daexcel = new OleDbDataAdapter(query, conn);
daexcel.Fill(dt);
conn.Close();
}
2) Doing some manipulations on datatable data before updating into table.
string strsqlst = string. Empty;
using (SqlConnection sqlConn = new SqlConnection(Connectionstring))
{
sqlConn.Open();
SqlCommand cmd;
StringBuilder sb = new StringBuilder();
sb.AppendLine("DataTable content:");
foreach (DataRow row in dt.Rows)
{
if (row.ItemArray[0].ToString() == "")
break;
strsqlst = "Update table Set col1= " + row.ItemArray[4].ToString() + " ,col2= " + row.ItemArray[5].ToString() + " where <Condition>'";
cmd = new SqlCommand(strsqlst, sqlConn);
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
sqlConn.Close();
}
The SqlCommand can be a whole SQL batch and is not limited to a single statement. So you can create a single large batch with 10,000 UPDATE statements, or divide it into for example 20 batches of 500 each.
In other words, you can create a single command with CommandText like this:
UPDATE [T] SET Col1='Value1', Col2='Value2' WHERE [Id] = 1;
...
UPDATE [T] SET Col1='Value999', Col2='Value1000' WHERE [Id] = 500;
That said, you should use parameters for all data values (to ensure SQL injection is not possible).
If you want to handle any errors (updates failing due to invalid data) you will need something a bit more sophisticated.

c# change parameter for sql in loop

I want to reuse a parameterized query in a loop.
(This query is a simple example, I don't think I could make the loop inside sql and just return the needed rows)
Instead of
private String sql = "SELECT v FROM t WHERE VAL_1 = #param_1";
for (int n=1;n<10;n++)
{
MySqlCommand m = new MySqlCommand(sql);
m.Parameters.AddWithValue("#param_1", n);
res = Convert.ToInt32(m.ExecuteScalar());
( ... )
}
I'd like to move the setup of the query outside the loop; something like
private String sql = "SELECT v FROM t WHERE VAL_1 = #param_1";
MySqlCommand m = new MySqlCommand(sql);
m.Parameters.Add("#param_1"); // does not exist
for (int n=1;n<10;n++)
{
m.Parameters.Set("#param_1", n); // does not exist
res = Convert.ToInt32(m.ExecuteScalar());
( ... )
}
So the server does not have to parse the same sql for each ilteration in loop.
Is that possible?
You can add a parameter with
m.Parameters.Add("#param_1", MySqlDbType.Int32);
and later in the loop assign a value with
m.Parameters["#param_1"].Value = n;
If you just need to run query for list of parms without do diffrent things on each result, You can create a string with a loop like that:
String where_str= VAL_1 = #param_1" OR VAL_1 = #param_2" OR VAL_1 = #param_3"...
String sql = "SELECT v FROM t WHERE " + where_str;
and then exec the query it will give the same result.
If you need to saparate results so you can make it with prepaerd statement. Also, I recommend you to read about stored procedure it may be the best soultion for you in some cases.
example for prepaerd statement: (more info in the link)
private static void SqlCommandPrepareEx(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(null, connection);
// Create and prepare an SQL statement.
command.CommandText =
"INSERT INTO Region (RegionID, RegionDescription) " +
"VALUES (#id, #desc)";
SqlParameter idParam = new SqlParameter("#id", SqlDbType.Int, 0);
SqlParameter descParam =
new SqlParameter("#desc", SqlDbType.Text, 100);
idParam.Value = 20;
descParam.Value = "First Region";
command.Parameters.Add(idParam);
command.Parameters.Add(descParam);
// Call Prepare after setting the Commandtext and Parameters.
command.Prepare();
command.ExecuteNonQuery();
// Change parameter values and call ExecuteNonQuery.
command.Parameters[0].Value = 21;
command.Parameters[1].Value = "Second Region";
command.ExecuteNonQuery();
}
}
Yes, this should be possible! Have a look for SQL Prepared Statements!
You can just use:
cmd = new MySqlCommand("SELECT * FROM yourTable WHERE condition=#val1", MySqlConn.conn);
In the loop add the parameters and prepare the command
cmd.Parameters.AddWithValue("#val1", value);
cmd.Prepare();
after the loop execute your query with
cmd.ExecuteNonQuery();
Yep, you can do all of those things but unless that's just an example you'd want to use IN with all the values or a join to a bulk loaded temp table if there are a large number of them. The reason is that each round trip to the DB has a significant overhead that you can reduce from n to 1 with either of those techniques.

Updating the value in column in SQLite

I want to pass a column2 to a function and update column3 with output of function. I have made func function to calculae the output. When i run the program
it only takes last value as input and outputs all columns with same value.What am i doing wrong?
sqlite1 = new SQLiteConnection("DataSource = D:/datab.db;version=3");
sqlite1.Open();
string query1 = "select * from ramrotable";
SQLiteCommand cmd = new SQLiteCommand(query1, sqlite1);
SQLiteDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("Age::" + reader["age"]);
//int data = Convert.ToInt16(reader["age"]);
string tempquery = string.Format("UPDATE ramrotable SET num =
func({0})",reader["age"]);
cmd = new SQLiteCommand(tempquery, sqlite1);
cmd.ExecuteNonQuery();
}
string query4 = "select * from ramrotable";
cmd = new SQLiteCommand(query4, sqlite1);
reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("Name: " + reader["name"] + " Age: " +
reader["age"] + " Num: " + reader["num"]);
}
You need to use a WHERE clause to tell SQLite which record to update exactly. Otherwise all records will be affected. Please make sure that in the WHERE clause you use a column (or a combination of columns) the identify the record uniquely!
Ideally, every record will have an ID column that contains a unique value and is the Primary Key.
I understand from the comments to the question that you actually want to update the value of the num column depending on a value from the age column of the same record, for all the records in the table.
To do this, you neither need to fetch all the records nor do you need to loop. All you need to do is invoke the following statement:
UPDATE ramrotable SET num = func(age)
This takes the value of the age column, passes it to func and sets the result as the new value for the num column for each record in the table.
So all of what you've written above can be shortened to
sqlite1 = new SQLiteConnection("DataSource = D:/datab.db;version=3");
sqlite1.Open();
cmd = new SQLiteCommand("UPDATE ramrotable SET num = func(age)", sqlite1);
cmd.ExecuteNonQuery();
When using
string tempquery = string.Format("UPDATE ramrotable SET num =
func({0})",reader["age"]);
you are updating each row with current func(age) value.
For updating each row with exact value you should use single command outside of the while loop:
string updatequery = "UPDATE ramrotable SET num = func(age)";
cmd = new SQLiteCommand(updatequery, sqlite1);
cmd.ExecuteNonQuery();

How to read the column SqlDataReader

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

How to get multiple rows from access database

I am trying to store each row of a access database, based on column Veh_ID. The found data may or may not be based on multiple rows. The code I am currently using can copy single row but if there are multiple results I can only get the first result. Can anyone please help me on this? I am noob when it comes to database. I tried to search Google but no one seems to be needing what I need. Here's the code I'm using:
string cmd1 = "SELECT * FROM Veh_checkup WHERE Veh_ID = " + veh_idd + "";
OleDbCommand cmd = new OleDbCommand(cmd1, con);
OleDbDataReader read = cmd.ExecuteReader();
read.Read();
veh_id=null;
int i=0;
foreach (var a in read)
{
try
{
veh_id = veh_id + " " + read[i].ToString();
}
catch { }
i++;
}
There are a few things I would point out, some specific to your question, some not:
USE PARAMETERISED QUERIES
Use OleDbDataReader.Read() to move to the next record.
Use a StringBuilder to concatenate strings in a loop, using string = string + "something" will create a new string on the heap with each iteration
Use using blocks on Disposable objects
catch { } is not good practice. You will never know an error occurred. At the very least you should log the error somewhere so you know you need to fix something.
OleDbDataReader[i] will get the data from column i for the current record being read, not the data from row i
Don't use SELECT * in production code, especially if you are only using 1 column. It is unnecessary data retrieval from the database and also unnecessary network traffic.
USE PARAMETERISED QUERIES
Okay, I know I included using parameterised queries twice, but that is how strongly I feel about it!
With the above changes made, your full code will become something like:
static string GetStringData(string vehID)
{
StringBuilder builder = new StringBuilder();
string cmd1 = "SELECT Column1 FROM Veh_checkup WHERE Veh_ID = #VehID";
using (OleDbConnection con = new OleDbConnection("YourConnectionString"))
using (OleDbCommand cmd = new OleDbCommand(cmd1, con))
{
con.Open();
cmd.Parameters.AddWithValue("#VehID", vehID);
using (OleDbDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
builder.Append(" " + reader.GetString(0));
}
}
}
return builder.ToString();
}
You are using the datareader in a wrong way. Instead of calling it once like you do, you have to call the datareader in a while loop like this:
while(theDataReader.Read())
{
// do your stuff in a loop now
}
So using this approach in your code would look something like this:
string cmd1 = "SELECT * FROM Veh_checkup WHERE Veh_ID = " + veh_idd + "";
OleDbCommand cmd = new OleDbCommand(cmd1, con);
OleDbDataReader read = cmd.ExecuteReader();
veh_id=null;
con.Open();
while(read.Read()) //your reader
{
try
{
veh_id = veh_id + " " + read[i].ToString();
}
catch { }
}

Categories

Resources