NET web form page and I am attempting to pass values from two different gridviews into a single sql column. I am still new to parameterized querys so I am not to sure what the syntax would be for this. Any thoughts or suggestions are greatly apperciated.
My obvioulsy broken code is below
void AddIEKGNote()
{
for (int y = 0; y < EKGImpGV.Rows.Count; y++)
{
try
{
String qry = "sp_InsertPatientNoteCarotidDuplexImp";
com.Open();
SqlCommand con = new SqlCommand(qry, com);
con.CommandType = CommandType.StoredProcedure;
con.Parameters.AddWithValue("#Value", EKGImpGV.Rows[y].Cells[1].Text);
con.Parameters.AddWithValue("#Value", GridView3.Rows[y].Cells[1].Text);
con.Parameters.AddWithValue("#Order_T", Label22.Text.Trim());
con.Parameters.AddWithValue("#P_ID", Label6.Text.Trim());
j = con.ExecuteNonQuery();
if (j > 0)
{
Response.Write(" SUCCESS ");
}
else
{
Response.Write(" ERROR ! ");
}
}
finally
{
com.Close();
EKGReportReader();
SearchData();
BaseEKG();
PostEKG();
ImpressionReader1();
ImpressionReader2();
ImpressionReader3();
ImpressionReader4();
ImpressionReader5();
ImpressionReader6();
}
}
}
This will not work since I am trying to pass Value twice in this function and my stored procedure and my sql table only has one "Value" column.
I want to be able to do something like this:
con.Parameters.AddWithValue("#Value", EKGImpGV.Rows[y].Cells[1].Text , GridView3.Rows[y].Cells[1].Text);
replace this
con.Parameters.AddWithValue("#Value", EKGImpGV.Rows[y].Cells[1].Text);
con.Parameters.AddWithValue("#Value", GridView3.Rows[y].Cells[1].Text);
with this
string val = EKGImpGV.Rows[y].Cells[1].Text + GridView3.Rows[y].Cells[1].Text;
con.Parameters.AddWithValue("#Value", val);
Related
I have labels "Hardwork" and 1 datagirdview display when load form. I use the code below to do the quantity comparison in the column "TotalTime". I want if the value is in column "TotalTime"> = 30 then labels "Harwork" + 1
but not run.the result is: specified cast is not valid.
Please, help me fix it
public void BtnSearch_Click(object sender, EventArgs e)
{
db = new DbConnector();
lbTotal.Text = "00";
db.fillDataGridView("select *from tbl_WorkLoad where TimeComplete Between'" + dateTimePicker1.Value.ToString("dd-MM-yy| HH:mm:tt") + "' and '" + dateTimePicker2.Value.ToString("dd-MM-yy| HH:mm:tt") + "'", dataGridView1);
const string HardWorkLabelText = "Hard Work Count: {0}";
const int HardWorkThreshold = 30;
try
{
IEnumerable<DataGridViewRow> rows = dataGridView1.Rows.Cast<DataGridViewRow>().Where(r => ((Int32)r.Cells["TotalTime"].Value) >= HardWorkThreshold);
lbHardwork.Text = string.Format(HardWorkLabelText, rows.Count());
{
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
lbTotaltime.Text = (Convert.ToString(double.Parse(lbTotaltime.Text) + double.Parse(dataGridView1.Rows[i].Cells[7].Value.ToString())));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
You have apart from the exception, you have few other issues in the code. But let us focus on the issue which you reported.
From the code, I understand that, you want to display the number of hardwork and also you want to display the total hardwork time.
Since you are looping thru the rows of gridview, you can calculate both of these in the for loop.
var hardworkCount = 0;
var totalTimeSum = 0.0;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
double totalTime = double.Parse(dataGridView1.Rows[i].Cells[7].Value.ToString());
if(totalTime >= HardWorkThreshold)
{
hardworkCount++;
}
totalTimeSum += totalTime;
}
lbHardwork.Text = hardworkCount.ToString();
lbTotaltime.Text = totalTimeSum.ToString();
You life would be a lot simpler if you stop pulling your data out of the datagridview, and just have your datagridview based off a datatable that holds the data. It might be this way already, but we can't see the definition of your filldatagridview method
Here's how I'd do it:
//assuming sql sevrer, use correct dataadapter for your db
using(var da = new SqlDataAdapter "select * from tbl_WorkLoad where TimeComplete Between #a and #b", "YOUR CONNECTION STRING HERE")){
da.SelectedCommand.Parameters.AddWithValue("#a", dateTimePicker1.Value);
da.SelectedCommand.Parameters.AddWithValue("#b", dateTimePicker2.Value);
var dt = new DataTable();
da.Fill(dt);
dataGridViewX.DataSource = dt;
lbHardwork.Text = dt.Compute("Count([TotalTime])", "[TotalTime] >= 30").ToString();
lbTotalTime.Text = dt.Compute("Sum([TotalTime])", "[TotalTime] >= 30").ToString();
}
The way you wrote your SQL is a pattern that risks SQL injection if used with strings - always use parameters in SQL. Always. There is never a reason not to when dealing with data values. See why, and also here
You should read this blog before using AddWithValue with strings in SQL Server. There are better ways to do parameters than AWV, but at the very least it would be preferable to use AddWithValue than what you're doing now
Don't access data in a gridview via the grid; bind the grid to a datatable and if you want data, access the datatable. If you want to get the datatable out of a grid at any point, you can use var dt = datagridviewX.DataSource as DataTable
I'm trying to update a column in a row with a new value. the new value is in a variable, and the value contain a new line in it.
This method receive as dictionary the column name and values need to change, and create a dynamic update command.
The Code is working for any other row in the table, but when a newline is involved, and SQL Error saying: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
var valueStr = "";
for (var i = 0; i < srcRow.Count; i++)
{
valueStr += string.Format("{0} = ?prm{1}", srcRow.Keys.ElementAt(i),i);
if (i < srcRow.Count - 1)
valueStr += ", ";
var query = string.Format("UPDATE {0} SET {1} WHERE {2}", table, valueStr, pkey);
try
{
using (var cmd = destConn.CreateCommand())
{
cmd.CommandText = query;
for (int i = 0; i < srcRow.Count; i++)
{
cmd.Parameters.AddWithValue("?prm" + i.ToString(),srcRow.Values.ElementAt(i));
}
cmd.ExecuteNonQuery();
}
}
Thanks
Shimshon
Try replacing \r\n with \\r\\n,
MySQL receive it and it will escape to database.
this is what i am trying to do after receiving string from the serial port. i get whitespace between the data so i put two loops to eliminate them. i want to recieve data spanning multiple columns and a single row for every single run of do while loop.. Thanks in Advance
string text = sp.readline();
for (int i = 0; i < text.Length; )
{
p = text[i].ToString();
if (p != " ")
{
do
{
x += text[i].ToString();
s = text[i].ToString();
i++;
} while (s != " ");
try
{
string col = "column" + no.ToString();
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "INSERT INTO testdata("+col+")VALUES(?data)";
cmd.Parameters.Add("?data", MySqlDbType.VarChar).Value = x;
cmd.ExecuteNonQuery();
x = "";
p = "";
no++;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
} i++;
}
Sorry to say, you cannot, in any dialect of SQL, provide a table or column name as a bindable variable (or parameter). If it's working for MySQL that's terrific, but if you change over to any other DBMS make and model, it will suddenly stop working.
Also, INSERT means create a new row. You'll either need to insert all the column values at once in a single INSERT statement, or figure out how to INSERT one row and then UPDATE it for each new column value.
if you want to insert a single row having multiple column, then for loop is not required
following is for three columns
int no = 2;
cmd.CommandText = "INSERT INTO testdata(?col1,?col2,?col3)VALUES(?data1,?data2,?data3)";
cmd.Parameters.Add("?col1", MySqlDbType.String).Value = col1;
cmd.Parameters.Add("?col2", MySqlDbType.String).Value = col2;
cmd.Parameters.Add("?col3", MySqlDbType.String).Value = col3;
cmd.Parameters.Add("?data1", MySqlDbType.VarChar).Value = x1;
cmd.Parameters.Add("?data2", MySqlDbType.VarChar).Value = x2;
cmd.Parameters.Add("?data3", MySqlDbType.VarChar).Value = x3;
cmd.ExecuteNonQuery();
I've data in DataTable with 2 rows and 3 columns. I want to insert that data into Oracle table.
How can I insert? please give me with some example.
And also
How can I pass datatable to storedprocedure in ORACLE...
I pass datatable in below mensioned manner, but datatable type problem is comming. how can I solve this?
cmd.Parameters.Add("#Details",dtSupplier);
(OR)
cmd.Parameters.Add("Details", DbType.Single).Value = dtSupplier.ToString();
want to insert dataset or a datatable into ORACLE,
create an ORACLE data adapter.
create a command object for insertion,
set the CommandType to StoredProcedure.
Update command of the data adapter,
pass the dataset or datatable as parameter.
like this:
OracleDataAdapter da = new OracleDataAdapter();
OracleCommand cmdOra = new OracleCommand(StoredProcedureName, Connection);
cmdOra.CommandType = CommandType.StoredProcedure;
da.InsertCommand = cmdOra;
da.Update(dsDataSet);
OR
if above dont work than pass datatable as xml prameter than than process it
For details check : ADO.NET DataTable as XML parameter to an Oracle/SQL Server Database Stored Procedure
OR
Check this thread on Oracle site : Thread: Pass data table to Oracle stored procedure
Check existing answer : How to Pass datatable as input to procedure in C#?
I'm very late for this answer, but I elaborated a bit to have some more readable (I hope) code, and to avoid all those .ToString() for the values so nulls and other less common values can be handled; here it is:
public void Copy(String tableName, DataTable dataTable)
{
var insert = $"insert into {tableName} ({GetColumnNames(dataTable)}) values ({GetParamPlaceholders(dataTable)})";
using (var connection = /*a method to get a new open connection*/)
{
for (var row = 0; row < dataTable.Rows.Count; row++)
{
InsertRow(dataTable, insert, connection, row);
}
}
}
private static void InsertRow(DataTable dataTable, String insert, OracleConnection connection, Int32 row)
{
using (var command = new OracleCommand(insert, connection))
{
AssembleParameters(dataTable, command, row);
command.ExecuteNonQuery();
}
}
private static void AssembleParameters(DataTable dataTable, OracleCommand command, Int32 row)
{
for (var col = 0; col < dataTable.Columns.Count; col++)
{
command.Parameters.Add(ParameterFor(dataTable, row, col));
}
}
private static OracleParameter ParameterFor(DataTable dataTable, Int32 row, Int32 col)
{
return new OracleParameter(GetParamName(dataTable.Columns[col]), dataTable.Rows[row].ItemArray.GetValue(col));
}
private static String GetColumnNames(DataTable data) => (from DataColumn column in data.Columns select column.ColumnName).StringJoin(", ");
private static String GetParamPlaceholders(DataTable data) => (from DataColumn column in data.Columns select GetParamName(column)).StringJoin(", ");
private static String GetParamName(DataColumn column) => $":{column.ColumnName}_param";
Hope this can be still useful to somebody
The best idea would be follow the step mentioned below
Create a transaction
Begin the transaction
Loop through you data table
call your procedure
If no error occurred commit transaction
else roll back transaction
Regarding this part of your question:
cmd.Parameters.Add("#Details",dtSupplier);
(OR)
cmd.Parameters.Add("Details", DbType.Single).Value = dtSupplier.ToString();
What is the type of the "Details" parameter? Is it a Single? Then you would have to pick one (1) value from your DataTable and pass it to your parameter, something like dtSupplier.Rows[0]["col"].
If you use dtSupplier.ToString() you are just making a string of the entire DataTable (which i guess will always be the type name of DataTable).
First of all, you need to add Oracle.DataAccess.dll as reference in Visual Studio. In most cases, you can find this dll in the directory C:\ProgramData\Oracle11g\product\11.2.0\client_1\ODP.NET\bin\2.x\Oracle.DataAccess.dll
If just you need to insert the records from DataTable to Oracle table, then you can call the below function. Consider that your DataTable name is dt.
string error = "";
int noOfInserts = DataTableToTable(dt,out error);
1. Without using Oracle Parameters(special character non-safe)
The definition of the function is given below. Here, we are just making the query dynamic for passing this as a sql statement to the InsertWithQuery function.
public int DataTableToTable(DataTable dt,out string error)
{
error = "";
for (int i = 0; i < dt.Rows.Count; i++)
{
finalSql = "INSERT INTO TABLENAME SELECT ";
for (int j = 0; j < dt.Columns.Count; j++)
{
colValue += "'" + dt.Rows[i][j].ToString() + "',";
}
colValue = colValue.Remove(colValue.Length - 1, 1);
finalSql += colValue + " FROM DUAL";
InsertWithQuery(finalSql, out error);
if (error != "")
return error;
inserts++;
colValue = "";
}
}
The code for InsertWithQuery function is given below. Here, in the connection string you have to place you database details like Host,Username,Password etc.
public int InsertWithQuery(string query, out string error)
{
error = "";
int rowsInserted = 0;
if (error == "")
{
OracleConnection con = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))(CONNECT_DATA=(SERVER=DEDICATED)(SID=)));User Id=;Password=");
OracleTransaction trans = con.BeginTransaction();
try
{
error = "";
OracleCommand cmd = new OracleCommand();
cmd.Transaction = trans;
cmd.Connection = con;
cmd.CommandText = query;
rowsInserted = cmd.ExecuteNonQuery();
trans.Commit();
con.Dispose();
return rowsInserted;
}
catch (Exception ex)
{
trans.Rollback();
error = ex.Message;
rowsInserted = 0;
}
finally
{
con.Dispose();
}
}
return rowsInserted;
}
2. With using Oracle Parameters(special character safe)
This can handle special characters like single quotes like scenarios in the column values.
public int DataTableToTable(DataTable dt,out string error)
{
error = "";
string finalSql = "";
List<string> colValue = new List<string>();
List<string> cols = new List<string>() {"COLUMN1","COLUMN2","COLUMN3"};
for (int i = 0; i < dt.Rows.Count; i++)
{
finalSql = "INSERT INTO TABLENAME(COLUMN1,COLUMN2,COLUMN3) VALUES(:COLUMN1,:COLUMN2,:COLUMN3) ";
for (int j = 0; j < dt.Columns.Count; j++)
{
colValue.Add(dt.Rows[i][j].ToString());
}
objDAL.InsertWithParams(finalSql,colValue,cols, out error);
if (error != "")
return error;
inserts++;
colValue.Clear();
}
}
And the InsertWithParams is given below
public string InsertWithParams(string sql, List<string> colValue, List<string> cols, out string error)
{
error = "";
try
{
OracleConnection con = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))(CONNECT_DATA=(SERVER=DEDICATED)(SID=)));User Id=;Password=");
OracleCommand command = new OracleCommand(sql, con);
for (int i = 0; i < colValue.Count; i++)
{
command.Parameters.Add(new OracleParameter(cols[i], colValue[i]));
}
command.ExecuteNonQuery();
command.Connection.Close();
}
catch (Exception ex)
{
error = ex.Message;
}
return null;
}
try {
//Suppose you have DataTable dt
string connectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;" +
#"Data Source='Give path of your access database file here';Persist Security Info=False";
OleDbConnection dbConn = new OleDbConnection(connectionString);
dbConn.Open();
using (dbConn)
{
int j = 0;
for (int i = 0; i < 2; i++)
{
OleDbCommand cmd = new OleDbCommand(
"INSERT INTO Participant_Profile ([column1], [column2] , [column3] ) VALUES (#c1 , #c2 , #c3 )", dbConn);
cmd.Parameters.AddWithValue("#c1", dt.rows[i][j].ToString());
cmd.Parameters.AddWithValue("#c2", dt.rows[i][j].ToString());
cmd.Parameters.AddWithValue("#c3", dt.rows[i][j].ToString());
cmd.ExecuteNonQuery();
j++;
}
}
}
catch (OleDbException exception)
{
Console.WriteLine("SQL Error occured: " + exception);
}
I know it's been a big WHILE upon the matter, but the same need: "to insert data from a datatable to an Oracle table" has happened to me. I found this thread. I also tried the answers and came to the conclusion that executing a
...
cmd.ExecuteNonQuery();
...
in a loop, is bad. Reeaaally bad. The first thing that is bad is performance, the second is unnecessary complexity, the third is unnecessary Oracle Objects (stored proc). The time it takes to complete, lets say 200 rows, is almost 1 minute and that's me rounding it down. So in the hope that someone else will find this helpful here's my experience.
I got stubborn and searched some more, so I found out this, true it's from 2018. But I'm in 2021 myself...
So the base code is:
using Oracle.ManagedDataAccess.Client; // you don't need other dll, just install this from nuget gallery
using System.Data;
public static void Datatable2Oracle(string tableName, DataTable dataTable)
{
string connString = "connection string";
OracleBulkCopy copy= new(connString, OracleBulkCopyOptions.UseInternalTransaction /*I don't know what this option does*/);
copy.DestinationTableName = tableName;
copy.WriteToServer(dataTable);
copy.Dispose();
}
This should match a raw oracle DDL performance:
create table table_name as select * from other_table_name
I am trying to insert multiple records into a table in one query using the MySqlCommand object in C# (using the MySQL Connector library).
The only way I know how to do this is by dynamically constructing the query myself and setting command.CommandType = CommandType.Text;
The problem with this method is that the fields are not escaped for quotes and such. I could write a function to escape the values myself I guess, but every article or question I have read on the internet appears to frown upon this, and says use command.Parameters as this more efficient and thorough.
My problem is that I don't know how to set the parameters for multiple rows. How can I do that?
Edit: This is for a commercial service which runs 24/7, so I need to find the most efficient way to do this. I'm not using stored procedures - is this is the only way or is there another?
public static string MySqlEscape(object value)
{
string val = value.ToString();
if (val.Contains("'"))
return val.Replace("'", "' + NCHAR(96) + '");
else
return val;
}
public void InsertProcessedData(long unprocessedID, long pagerID, long firmwareRelativeProtocolID, DataTable processedData)
{
using(processedData)
{
string paramColNames = string.Empty;
for(int i =1;i<=processedData.Columns.Count;i+=1)
{
paramColNames+=string.Format("Param{0}",i);
if(i!=processedData.Columns.Count)
paramColNames+=",";
}
string SQL = "INSERT INTO gprs_data_processed (#UnprocessedID,#PagerID,#FirmwareRelativeProtocolID,"+paramColNames+") VALUES ";
for (int i = 0; i < processedData.Rows.Count;i+=1)
{
SQL += string.Format("({0},{1},{2},", unprocessedID, pagerID, firmwareRelativeProtocolID);
for (int c = 0; c < processedData.Columns.Count; c += 1)
{
SQL += string.Format("'{0}'", MySqlEscape(processedData.Rows[i][c]));
if (i != processedData.Columns.Count)
SQL += ",";
}
SQL+=")";
if (i + 1 != processedData.Rows.Count)
SQL += ",";
else
SQL += ";";
}
using (MySqlConnection connection = new MySqlConnection(_connection))
{
connection.Open();
using (MySqlCommand command = connection.CreateCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = SQL;
command.ExecuteNonQuery();
}
connection.Close();
}
}
}
I'm not sure on how to create a single command. What I do is create a method that uses parameters and then pass in the values that I want to run one at a time.
My method:
public void Insert(string strSQL, string[,] parameterValue)
{
//open connection
if (this.OpenConnection() == true)
{
//create command and assign the query and connection from the constructor
MySqlCommand cmd = new MySqlCommand(strSQL, connection);
//add parameters
for (int i = 0; i < (parameterValue.Length / 2); i++)
{
cmd.Parameters.AddWithValue(parameterValue[i, 0], parameterValue[i, 1]);
}
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
I have ended up just using the function I have written already as it does it all in one command, and use:
public static string MySqlEscape(object value)
{
string val = value.ToString();
if (val.Contains("'"))
return val.Replace("'", "''");
else
return val;
}
It works fine so I will see how things go.