Arraylist of arraylist...in c# - c#

I need to get data from a SQL query, I have a method that returns me an arraylist of arraylist, but I am not able to show me the data returned by the query sql.
I write the method returns the sql query:
public ArrayList ejecutarSelect(string sentenciaSQL){
if (this.conn.State != System.Data.ConnectionState.Open)this.Conectar();
ArrayList rows = new ArrayList();
MySqlCommand cmd = new MySqlCommand(sentenciaSQL, this.conn);
try
{
MySqlDataReader dataReader = cmd.ExecuteReader();
if (dataReader.HasRows)
{
while (dataReader.Read())
{
ArrayList row = new ArrayList();
for (int i = 0; i < dataReader.FieldCount; i++) row.Add(dataReader.GetString(i));
rows.Add(row);
}
}
dataReader.Close();
}
catch (Exception e)
{
CLog.log("ERROR (CDBMgr): " + e.Message);
return null;
}
return rows;
}

row.Add(dataReader[i].ToString());
See SqlDataReader.GetString Method.
It says
No conversions are performed; therefore, the data retrieved must already be a string.
So ..

Related

DELETE C# SqlCommand: Subquery returned more than 1 value

I have an error doing either a DELETE or INSERT using a C# SqlCommand; database is SQL server.
The SQL statement is
DELETE FROM [table_name]
WHERE id = 'some_id';
which is pretty simple.
id is a column name with datatype varchar(15) that can be NULL; some_id has 15 characters.
First, to verify that only 1 row with that ID exists, this SELECT query was made that returns no errors
SELECT *
FROM [table_name]
WHERE id = 'some_id';
returns 1 row
The error on the DELETE is
System.Data.SqlClient.SqlException (0x80131904): Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
This error can happen when more than 1 row satisfy the criteria of the query; clearly not the case here
What is puzzling is that doing the same DELETE query using the C ODBC API there is no error; so it seems the problem is in the C# code
C# code that calls DELETE:
public int execute(string sql)
{
SqlConnection conn = new SqlConnection(conn_str);
try
{
conn.Open();
SqlCommand command = new SqlCommand(sql, conn);
command.ExecuteNonQuery();
conn.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return -1;
}
return 0;
}
C# code that calls SELECT:
public List<List<string>> select(string sql)
{
Stopwatch sw = new Stopwatch();
sw.Start();
List<List<string>> rows = null;
SqlConnection conn = new SqlConnection(conn_str);
try
{
conn.Open();
SqlDataReader reader = null;
SqlCommand command = new SqlCommand(sql, conn);
reader = command.ExecuteReader();
int nbr_cols = reader.FieldCount;
int nbr_rows = 0;
rows = new List<List<string>>();
while (reader.Read())
{
nbr_rows++;
List<string> col = new List<string>();
for (int idx_col = 0; idx_col < nbr_cols; idx_col++)
{
string str = reader[idx_col].ToString();
col.Add(str);
}
rows.Add(col);
}
reader.Close();
conn.Close();
sw.Stop();
Console.WriteLine("Time to get {0} rows: {1} msec", nbr_rows, sw.ElapsedMilliseconds);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return rows;
}
C++ DELETE code with no error
std::string sql = "DELETE FROM [some_table] WHERE ID='some_id';";
if (query.exec_direct(sql) < 0)
{
std::cout << sql;
}
where the function exec_direct is here
https://github.com/pedro-vicente/lib_odbc/blob/master/odbc.cc
thanks
EDIT
adding link to DELETE documentation
https://learn.microsoft.com/en-us/sql/t-sql/statements/delete-transact-sql?view=sql-server-2017

Need a little bit of help finishing a generic MySQL select method

General info
I'm busy writing my own MySQL database class inside C#. At the moment I'm trying to write a Select method that accepts a select query and returns a List with all the data. I'm still very new to C# so if my approach to this problem is wrong, please do not hesitate to tell me.
The problem
Right now my method expects 2 parameters. The query and the number of columns selected by the query. With that info I prepare my List and start filling it up. To do this I'm relying on the amount of columns with a foreach loop. However, I have no idea on how to get the correct column names
when adding to the List. Aside from that, I'm not sure if my approach is going to work. So I hope you guys would like to take a look at my method and help me out finishing it.
The method
public List<string>[] Select(string query, int items)
{
//Create a list to store the result
List<string>[] resultList = new List<string>[items];
for(int i = 0; i < items; i++)
{
resultList[i] = new List<string>();
}
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand cmd = new MySqlCommand(query, connection);
//Create a data reader and Execute the command
MySqlDataReader dataReader = cmd.ExecuteReader();
//Read the data and store them in the list
while (dataReader.Read())
{
for(int j = 0; j < items; j++)
{
resultList[j].Add(dataReader["columnName_here"] + "");
}
}
//close Data Reader
dataReader.Close();
//close Connection
this.CloseConnection();
//return list to be displayed
return resultList;
}
else
{
return resultList;
}
}
MySqlDataReader is derived from System.Data.Common.DbDataReader, so you can use this code to get the columns:
for (int c = 0; c < dataReader.FieldCount; c++)
{
string name = dataReader.GetName(c);
Type type = dataReader.GetFieldType(c);
}

How to get all my database table values in a listbox with the for statement C#

As a beginner in C# I am having some problems with getting all my values (and only the values - not the field names) out of my database table and list them in my listbox.
I did some research and found out that I could get all the field names of a specific table with the following code:
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "select * from MyTable where Month='January'";
command.CommandText = query;
OleDbDataReader reader = command.ExecuteReader();
var columns = listBox5;
for (int i = 0; i < reader.FieldCount; i++)
{
if (reader.GetName(i) != "Month" && reader.GetName(i) != "Id")
{
columns.Items.Add(reader.GetName(i));
}
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
This works perfectly for listing the field names (and not the field names Month and ID). Though now I also need to list all my values (that match with the corresponding field names). At first I thought to add them at the same time with the field names (above code) but this was to complicated for me. So then I try'd to list the values in another listbox with kinda the same code, but instead of using the GetName I used the GetValue. See code below:
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "select * from MyTable";
command.CommandText = query;
OleDbDataReader reader = command.ExecuteReader();
var columns2 = listBox6;
for (int i = 0; i < reader.FieldCount; i++)
{
columns2.Items.Add(reader.GetValue(i).ToString());
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
This doesn't work though. I am getting the following error:
ErrorSystem.InvalidOperationException: Data doesn't exist for the row/column at line ...
On this line:
columns2.Items.Add(reader.GetValue(i).ToString());
You need to call Read() on your reader before you can read records:
var columns2 = listBox6;
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
columns2.Items.Add(reader.GetValue(i).ToString());
}
}
From MSDN:
Advances the SqlDataReader to the next record. The default position of the SqlDataReader is before the first record. Therefore, you must call Read to begin accessing any data.

OracleDataReader & datadridview list

I try read data from oracle db and set data to datagridview component but I dont know where is the problem datagridview is empty, if I test reader throught while loop and get values I see all rows:
CODE:
Dbc dbc = new Dbc();
dbc.connect();
try
{
String sql = "SELECT * FROM " + _tname;
OracleCommand comm = new OracleCommand(sql, dbc.getConnection());
OracleDataReader reader = comm.ExecuteReader();
tableListhist.ColumnCount = reader.FieldCount;
for (int i = 0; i < reader.FieldCount; ++i)
{
tableListhist.Columns[i].HeaderText = reader.GetName(i).ToLower();
}
//tableListhist.DataMember = _tname;
tableListhist.DataSource = reader;
reader.Close();
tableListhist.ReadOnly = true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
dbc.close();
}
But datagridview is empty :(
Usually you pass a DataTable or a DataSet as value for the DataSource property
DataTable dt = new DataTable();
dt.Load(reader);
tableListhist.DataSource = dt;

How to Insert Data from DataTable to Oracle Database Table :

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

Categories