How to speed up odbc insert - c#

So what I'm doing is reading a lot of data from remote Nettezza database and inserting them into another remote Oracle database. For that I'm using ODBC driver. The problem is that there is a lot of data and it takes too much time. How can I speed up?
Here is what I do:
First I create connection and command for inserting:
String connect = "Driver={Microsoft ODBC for Oracle};CONNECTSTRING=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=myprt))(CONNECT_DATA=(SERVICE_NAME=myname)));Uid=uid;Pwd=pass";
connection = new OdbcConnection(connect);
connection.Open();
String q = #"INSERT INTO TEST (id)
VALUES (?)";
myCommand = new OdbcCommand(q,connection);
Then I read data from netteza:
String connect = "Driver={NetezzaSQL};servername=server;port=5480;database=db; username=user;password=pass;
string query = #"SELECT T2.LETO_MESEC, T1.*
FROM data T1
JOIN datga2 T2 ON T2.ID = T1.EFT_ID
WHERE T2.LETO_MESEC = '" + mesec + #"'";
using (OdbcConnection connection = new OdbcConnection(connect))
{
try
{
OdbcCommand command = new OdbcCommand(query, connection);
connection.Open();
OdbcDataReader reader = command.ExecuteReader();
int counter=0;
while (reader.Read())
{
int id_first = reader.GetInt32(5);
insertOracle(id_first);
}
}
catch (Exception e)
{
Console.WriteLine("ne dela" + e.ToString());
}
}
And finally my insert :
public void insertOracle(int id_first)
{
try
{
myCommand.Parameters.Clear();
myCommand.Parameters.Add(new OdbcParameter("id", id_first));
myCommand.ExecuteNonQuery();
}
catch (Exception e)
{
Console.WriteLine("ne dela" + e.ToString());
}
}
I noticed that these commit in every line, so how to remove that and speed it up. Right now it takes about 10 minutes for 20000 rows.

Single inserts are always going to be slow -- start processing the data in arrays, selecting a batch of ID's from the source system and loading an array to the target.
Here is an article which might be helpful. http://www.oracle.com/technetwork/issue-archive/2009/09-sep/o59odpnet-085168.html

Related

C# ASP.Net Processing Issue - Reading Table While Deleting Rows

Simply, I have an application that has one page that deletes and then re-adds/refreshes the records into a table every 30 seconds. I have another page that runs every 45 seconds that reads the table data and builds a chart.
The problem is, in the read/view page, every once in a while I get a 0 value (from a max count) and the chart shows nothing. I have a feeling that this is happening because the read is being done at the exact same time the delete page has deleted all the records in the table but has not yet refreshed/re-added them.
Is there a way in my application I can hold off on the read when the table is being refreshed?
Best Regards,
Andy
C#
ASP.Net 4.5
SQL Server 2012
My code below is run in an ASP.Net 4.5 built Windows service. It deletes all records in the ActualPlot table and then refreshes/adds new records from a text file every 30 seconds. I basically need to block (lock?) any user from reading the ActualPlot table while the records are being deleted and refreshed. Can you PLEASE help me change my code to do this?
private void timer1_Tick(object sender, ElapsedEventArgs e)
{
// Open the SAP text files, clear the data in the tables and repopulate the new SAP data into the tables.
var cnnString = ConfigurationManager.ConnectionStrings["TaktBoardsConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(cnnString);
SqlConnection conndetail = new SqlConnection(cnnString);
SqlConnection connEdit = new SqlConnection(cnnString);
SqlCommand cmdGetProductFile = new SqlCommand();
SqlDataReader reader;
string sql;
// Delete all the records from the ActualPlot and the ActualPlotPreload tables. We are going to repopulate them with the data from the text file.
sql = "DELETE FROM ActualPlotPreload";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Delete Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conn.Close();
}
sql = "DELETE FROM ActualPlot";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Delete Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conn.Close();
}
// Read the SAP text file and load the data into the ActualPlotPreload table
sql = "SELECT DISTINCT [BoardName], [ProductFile], [ProductFileIdent] FROM [TaktBoards].[dbo].[TaktBoard] ";
sql = sql + "JOIN [TaktBoards].[dbo].[Product] ON [Product].[ProductID] = [TaktBoard].[ProductID]";
cmdGetProductFile.CommandText = sql;
cmdGetProductFile.CommandType = CommandType.Text;
cmdGetProductFile.Connection = conn;
conn.Open();
reader = cmdGetProductFile.ExecuteReader();
string DBProductFile = "";
string DBTischID = "";
string filepath = "";
string[] cellvalues;
DateTime dt, DateCheckNotMidnightShift;
DateTime ldSAPFileLastMod = DateTime.Now;
string MyDateString;
int FileRecordCount = 1;
while (reader.Read())
{
DBProductFile = (string)reader["ProductFile"];
DBTischID = (string)reader["ProductFileIdent"];
filepath = "c:\\inetpub\\wwwroot\\WebApps\\TaktBoard\\FilesFromSAP\\" + DBProductFile;
FileInfo fileInfo = new FileInfo(filepath); // Open file
ldSAPFileLastMod = fileInfo.LastWriteTime; // Get last time modified
try
{
StreamReader sr = new StreamReader(filepath);
FileRecordCount = 1;
// Populate the AcutalPlotPreload table from with the dates from the SAP text file.
sql = "INSERT into ActualPlotPreload (ActualDate, TischID) values (#ActualDate, #TischID)";
while (!sr.EndOfStream)
{
cellvalues = sr.ReadLine().Split(';');
if (FileRecordCount > 1 & cellvalues[7] != "")
{
MyDateString = cellvalues[7];
DateTime ldDateCheck = DateTime.ParseExact(MyDateString, "M/dd/yyyy", null);
DateTime dateNow = DateTime.Now;
string lsDateString = dateNow.Month + "/" + dateNow.Day.ToString("d2") + "/" + dateNow.Year;
DateTime ldCurrentDate = DateTime.ParseExact(lsDateString, "M/dd/yyyy", null);
string lsTischID = cellvalues[119];
if (ldDateCheck == ldCurrentDate)
{
try
{
conndetail.Open();
SqlCommand cmd = new SqlCommand(sql, conndetail);
cmd.Parameters.Add("#ActualDate", SqlDbType.DateTime);
cmd.Parameters.Add("#TischID", SqlDbType.VarChar);
cmd.Parameters["#TischID"].Value = cellvalues[119];
MyDateString = cellvalues[7] + " " + cellvalues[55];
dt = DateTime.ParseExact(MyDateString, "M/dd/yyyy H:mm:ss", null);
cmd.Parameters["#ActualDate"].Value = dt;
// Ignore any midnight shift (12am to 3/4am) units built.
DateCheckNotMidnightShift = DateTime.ParseExact(cellvalues[7] + " 6:00:00", "M/dd/yyyy H:mm:ss", null);
if (dt >= DateCheckNotMidnightShift)
{
cmd.ExecuteNonQuery();
}
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conndetail.Close();
}
}
}
FileRecordCount++;
}
sr.Close();
}
catch
{ }
finally
{ }
}
conn.Close();
// Get the unique TischID's and ActualDate from the ActualPlotPreload table. Then loop through each one, adding the ActualUnits
// AcutalDate and TischID to the ActualPlot table. For each unique TischID we make sure that we reset the liTargetUnits to 1 and
// count up as we insert.
SqlCommand cmdGetTischID = new SqlCommand();
SqlDataReader readerTischID;
int liTargetUnits = 0;
string sqlInsert = "INSERT into ActualPlot (ActualUnits, ActualDate, TischID) values (#ActualUnits, #ActualDate, #TischID)";
sql = "SELECT DISTINCT [ActualDate], [TischID] FROM [TaktBoards].[dbo].[ActualPlotPreload] ORDER BY [TischID], [ActualDate] ASC ";
cmdGetTischID.CommandText = sql;
cmdGetTischID.CommandType = CommandType.Text;
cmdGetTischID.Connection = conn;
conn.Open();
readerTischID = cmdGetTischID.ExecuteReader();
DBTischID = "";
DateTime DBActualDate;
string DBTischIDInitial = "";
while (readerTischID.Read())
{
DBTischID = (string)readerTischID["TischID"];
DBActualDate = (DateTime)readerTischID["ActualDate"];
if (DBTischIDInitial != DBTischID)
{
liTargetUnits = 1;
DBTischIDInitial = DBTischID;
}
else
{
liTargetUnits++;
}
try
{
conndetail.Open();
SqlCommand cmd = new SqlCommand(sqlInsert, conndetail);
cmd.Parameters.Add("#ActualUnits", SqlDbType.Real);
cmd.Parameters.Add("#ActualDate", SqlDbType.DateTime);
cmd.Parameters.Add("#TischID", SqlDbType.VarChar);
cmd.Parameters["#TischID"].Value = DBTischID;
cmd.Parameters["#ActualDate"].Value = DBActualDate;
cmd.Parameters["#ActualUnits"].Value = liTargetUnits;
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conndetail.Close();
}
}
conn.Close();
Library.WriteErrorLog("SAP text file data has been imported.");
}
If the data is being re-added right back after the delete (basically you know what to re-add before emptying the table), you could have both operation within the same SQL transaction, so that the data will be available to the other page only when it has been re-added.
I mean something like that :
public bool DeleteAndAddData(string connString)
{
using (OleDbConnection conn = new OleDbConnection(connString))
{
OleDbTransaction tran = null;
try
{
conn.Open();
tran = conn.BeginTransaction();
OleDbCommand deleteComm = new OleDbCommand("DELETE FROM Table", conn);
deleteComm.ExecuteNonQuery();
OleDbCommand reAddComm = new OleDbCommand("INSERT INTO Table VALUES(1, 'blabla', 'etc.'", conn);
reAddComm.ExecuteNonQuery();
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
return false;
}
}
return true;
}
If your queries don't take too long to execute, you can start the two with a difference of 7.5 seconds, as there is a collision at every 90 seconds when the read/write finishes 3 cycles, and read/view finishes 2 cycles.
That being said, it's not a fool-proof solution, just a trick based on assumptions, in case you wan't to be completely sure that read/view never happens when read/write cycle is happening, try considering having a Read Lock. I would recommend reading Understanding how SQL Server executes a query and Locking in the Database Engine
Hope that helps.
I would try a couple of things:
Make sure your DELETE + INSERT operation is occurring within a single transaction:
BEGIN TRAN
DELETE FROM ...
INSERT INTO ...
COMMIT
If this isn't a busy table, try locking hints your SELECT statement. For example:
SELECT ...
FROM Table
WITH (UPDLOCK, HOLDLOCK)
In the case where the update transactions starts while your SELECT statement is running, this will cause that transaction to wait until the SELECT is finished. Unfortunately it will block other SELECT statements too, but you don't risk reading dirty data.
I was not able to figure this out but I changed my code so the program was not deleting all the rows in the ActualPlot table but checking to see if the row was there and if not adding the new row from the text file.

How to query a Foxpro .DBF file with .NDX index file using the OLEDB driver in C#

I have a Foxpro .DBF file. I am using OLEDB driver to read the .DBF file. I can query the DBF and utilize its .CDX index file(cause it is automatically opened). My problem is that I want to query it with the .NDX index file (which is not automatically opened when the .DBF is opened). How can I open the .NDX file in C# using OLEDB driver cause the DBF is really big to search for a record without the index? Thanks all! Here is the code I am using to read the DBF.
OleDbConnection oleDbConnection = null;
try
{
DataTable resultTable = new DataTable();
using (oleDbConnection = new OleDbConnection("Provider=VFPOLEDB.1;Data Source=P:\\Test\\DSPC-1.DBF;Exclusive=No"))
{
oleDbConnection.Open();
if (oleDbConnection.State == ConnectionState.Open)
{
OleDbDataAdapter dataApdapter = new OleDbDataAdapter();
OleDbCommand command = oleDbConnection.CreateCommand();
string selectCmd = #"select * from P:\Test\DSPC-1 where dp_file = '860003'";
command.CommandType = CommandType.Text;
command.CommandText = selectCmd;
dataApdapter.SelectCommand = command;
dataApdapter.Fill(resultTable);
foreach(DataRow row in resultTable.Rows)
{
//Write the data of each record
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
try
{
oleDbConnection.Close();
}
catch (Exception e)
{
Console.WriteLine("Failed to close Oledb connection: " + e.Message);
}
}
ndx files wouldn't be opened by default and those are a thing of the past really, why wouldn't you simply add your index to your CDX. If it is not an option, then ExecScript suggestion by DRapp is what you can do. He was very close. Here is how you could do that:
string myCommand = #"Use ('P:\Test\DSPC-1') alias myData
Set Index To ('P:\Test\DSPC-1_Custom.NDX')
select * from myData ;
where dp_file = '860003' ;
into cursor crsResult ;
nofilter
SetResultset('crsResult')";
DataTable resultTable = new DataTable();
using (oleDbConnection = new OleDbConnection(#"Provider=VFPOLEDB;Data Source=P:\Test"))
{
oleDbConnection.Open();
OleDbCommand command = new OleDbCommand("ExecScript", oleDbConnection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("code", myCommand);
resultTable.Load(cmd.ExecuteReader());
oleDbConnection.Close();
}
Your connection string should only reference the PATH to where the .dbf files are located.
Then, your query is just by the table name.
new OleDbConnection("Provider=VFPOLEDB.1;Data Source=P:\\Test\\;Exclusive=No"))
selectCmd = #"select * from DSPC-1 where dp_file = '860003'";
As for using the .NDX, how / where was that created... Is that an old dBASE file you are using the Visual Foxpro driver for?
If it is a separate as described, you might need to do via an ExecScript() to explicitly open the file first WITH the index, THEN run your query. This is just a SAMPLE WITH YOUR FIXED value. You would probably have to PARAMETERIZE it otherwise you would be open to sql-injection.
cmd.CommandText = string.Format(
#"EXECSCRIPT('
USE DSPC-1 INDEX YourDSPC-1.NDX
SELECT * from DSPC-1 where dp_file = '860003'" );
Also, you might have issue with your table names being hyphenated, you may need to wrap it in [square-brackets], but not positive if it is an issue.

C# Mysql multiple queries

Im trying to build up a little status-tool. I need to get results of multiple queries (about 4-5). The general connection-setup and 'how-to-read-data' is already done but I cant figure out how the another query executed.
Everything I found while searching for it is for the SqlClient. Im totally overcharged with this.
Here is my code so far (be patient, im a newbie to this):
private void button1_Click(object sender, EventArgs e)
{
if(listView1.Items.Count > 1)
{
listView1.Items.Clear();
}
var listMember = new List<string>{};
var listOnline = new List<string>{};
// SQL PART //
string connString = "Server=10*****;Port=3306;Database=e***;Uid=e***;password=********************;";
MySqlConnection conn = new MySqlConnection(connString);
MySqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT fullname,online FROM member WHERE active = '1' ORDER BY online DESC";
try
{
conn.Open();
}
catch (Exception ex)
{
listView1.Items.Add("Error: " + ex);
}
MySqlDataReader reader = command.ExecuteReader();
while(reader.Read())
{
listMember.Add(reader["fullname"].ToString());
listOnline.Add(reader["online"].ToString());
}
conn.Close();
// SQL ENDING //
// SET ENTRIES TO LISTVIEW //
int counter = 0;
foreach(string member in listMember)
{
ListViewItem item = new ListViewItem(new[] { member, listOnline.ElementAt(counter) });
item.ForeColor = Color.Green;
listView1.Items.Add(item);
counter++;
}
}
Im not really sure how the design/layout will look like in the end, so I would like to just append the results to lists in the sql-part to process the data later out of the lists.
Do I really have to setup a complete new connection after conn.Close()? Or is there any other way? I can just imagine: 5 queries with their own connection,try,catch and 2 loops... this will get about 100-200 lines just for getting the results out of 5 queries. Isnt that a bit too much for such an easy thing?
Hope for some help.
Greetings.
According to the new comments my latest code:
Top:
public partial class Form1 : Form
{
public static string connString = "Server=10****;Port=3306;Database=e****;Uid=e****;password=****;";
public Form1()
{
InitializeComponent();
MySqlConnection conn = new MySqlConnection(connString); // Error gone!
}
Body part:
public void QueryTwoFields(string s, List<string> S1, List<string> S2)
{
try
{
MySqlCommand cmd = conn.CreateCommand(); // ERROR: conn does not exist in the current context.
cmd.CommandType = CommandType.Text;
string command = s;
cmd.CommandText = command;
MySqlDataReader sqlreader = cmd.ExecuteReader();
while (sqlreader.Read())
{
S1.Add(sqlreader[0].ToString());
S2.Add(sqlreader[1].ToString());
}
sqlreader.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
if(listView1.Items.Count > 1)
{
listView1.Items.Clear();
}
var listMember = new List<string>{};
var listOnline = new List<string>{};
using (conn) // ERROR: conn does not exist in the current context.
{
conn.Open();
///...1st Query
QueryTwoFields("SELECT fullname,online FROM member WHERE active = '1' ORDER BY online DESC",listMember,listOnline);
//...2nd query
//QueryTwoFields("your new Select Statement", otherList, otherList);
}
}
You don't have to close connection every time you execute one query rarher than close the sqlreader assigned to that connection. Finally when all of your queries have been executed you close the connection. Consider also the use of using:
You cal also define a method for execution your Query in order for your code not to be repetive:
public void QueryTwoFields(string s, List<string> S1, List<string> S2)
///Select into List S1 and List S2 from Database (2 fields)
{
try
{
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
string command = s;
cmd.CommandText = command;
MySqlDataReader sqlreader = cmd.ExecuteReader();
while (sqlreader.Read())
{
S1.Add(sqlreader[0].ToString());
S2.Add(sqlreader[1].ToString());
}
sqlreader.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
if(listView1.Items.Count > 1)
{
listView1.Items.Clear();
}
var listMember = new List<string>{};
var listOnline = new List<string>{};
// SQL PART //
using (conn)
{
conn.Open();
///...1st Query
QueryTwoFields("SELECT fullname,online FROM member WHERE active = '1' ORDER BY online DESC",listmember,listonline)
//...2nd query
QueryTwoFields("your new Select Statement",myOtherList1,myOtherlist2)
....
}
}
EDIT :
Take in mind you cant define QueryTwoFields method inside button handler. You must define it outside (see code above).
Also Define your connection data in the start of the programm:
namespace MyProject
{
/// <summary>
/// Defiine your connectionstring and connection
/// </summary>
///
public partial class Form1 : Form
{ public static string connString = "Server=10*****;Port=3306;Database=e***;Uid=e***;password=********************;";
MySqlConnection conn = new MySqlConnection(connString);
.........
Datatables are fantastic
Using a data table is a nice way to do both read and write. And it comes with the luxury of eveything you can do with a datatable - like asssigning it directly to a datagrid control, sorting, selecting and deleting while disconnected.
The sample below assumes a MySqlConnection conection property managed by calls to your own OpenConnection() and CloseConnection() methods not shown.
Simple datatable read demo:
public DataTable Select(string query = "")
{
//Typical sql: "SELECT * FROM motorparameter"
DataTable dt = new DataTable();
//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();
dt.Load(dataReader);
//close Data Reader
dataReader.Close();
//close Connection
this.CloseConnection();
//return data table
return dt;
}
else
{
return dt;
}
}
In case of writing back the datatable to the database - supply the SQL you used in the read (or would have used to read to the data table):
public void Save(DataTable dt, string DataTableSqlSelect)
{
//Typically "SELECT * FROM motorparameter"
string query = DataTableSqlSelect;
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand mySqlCmd = new MySqlCommand(query, connection);
MySqlDataAdapter adapter = new MySqlDataAdapter(mySqlCmd);
MySqlCommandBuilder myCB = new MySqlCommandBuilder(adapter);
adapter.UpdateCommand = myCB.GetUpdateCommand();
adapter.Update(dt);
//close Connection
this.CloseConnection();
}
else
{
}
}
The neat thing the datatable is extremely flexible. You can run your own selects against the table once it contains data and before writing back you can set or reset what rows needs updating and by default the datatable keeps track of what rows you update in the table. Do not forget primary key column(s) for all tables in the db.
For multiple queries consider if possible using a join between the database tables or same table if data related or use a UNION sql syntax if column count and type of data is the same. You can allways "create" your extra column in the select to differ what data comes from what part of the UNION.
Also consider using CASE WHEN sql syntax to conditionally select data from different sources.

SQL query doesn't get inserted

I've been trying to get my query to work for some time it runs but doesn't insert anything nor does it return any errors.
The database connection is open and is successfuly connection.
The Table is called errorlog and holds the following data
- id (int autoincremental, Primary key, Unique)
- exception (varchar)
- time (DateTime)
exception = String(error message)
time = DateTime.Now
Here's the code:
public void insertError(string error, DateTime time)
{
SqlCeParameter[] sqlParams = new SqlCeParameter[]
{
new SqlCeParameter("#exception", error),
new SqlCeParameter("#time", time)
};
try
{
cmd = new SqlCeCommand();
cmd.Connection = connection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO errorlog (exception, time) VALUES(#exception, #time)";
cmd.Parameters.AddRange(sqlParams);
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
Any help would be appreciated, Thanks in advance.
EDIT
Removed quotes around #exception
Heres the connection:
protected DataController()
{
try
{
string appPath = System.IO.Path.GetDirectoryName(Assembly.GetAssembly(typeof(DataController)).CodeBase).Replace(#"file:\", "") + #"\";
string strCon = #"Data Source = " + appPath + #"Data\EasyShop.sdf";
connection = new SqlCeConnection(strCon);
}
catch (Exception e)
{
}
connection.Open();
}
Finally the way it gets called:
public bool log(string msg, bool timestamp = true)
{
DataController dc = DataController.Instance();
dc.insertError(msg, DateTime.Today);
return true;
}
Debug your application and see if connection points exactly to the
database you want. Also check if you look for the inserted records
in the same database.
If your connection belongs to the transaction, check if it's committed. You will not see those records inserted until transaction is committed.
It seems to me, that you INSERT is wrong. Remove quotes around #exception
Open SQL Server Profiler, connect to your database and check if your INSERT appears in there.

Using Multiple Data Readers

I am developing a WinForm Application in C Sharp on the .net framework.
The database string I am using as of now is
<add key="Conn" value="Data Source=MNTCON016; Database=Overtime_Calculator;Trusted_Connection=True;MultipleActiveResultSets=true" />
As I am using Microsoft SQL Server 2005 for development, I can use 2 data readers simultaneously using the MultipleActiveResultSets property to true as mentioned above.
The Method used to invoke the 2 data readers is as follows:
public static void SignUpControllerDay(DateTime Date, System.Windows.Forms.DataGridView PassedGrid)
{
string sql_SignUp = String.Format(#"SELECT Emp_ID as Emp_ID, Name as Name, Sum(Sum) as Sum FROM
(SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID,
e.First_Name+ ' ' +e.Last_Name as Name,
o.Quantity as Sum
FROM Employee e,OT_Hours o,Position p,Signup_Sheet s
WHERE e.Emp_ID=o.Emp_ID
and e.Emp_ID = s.Employee_ID
and s.Day_Shift = 1
and e.Position_ID = p.Position_ID
and p.Position_Name = 'Controller'
and o.Quantity NOT IN(0.3)
and s.Date = '{0}'
and o.Date <= CONVERT(VARCHAR,'{0}',101) AND o.Date > CONVERT(VARCHAR,DATEADD(YYYY,-1,'{0}'),101) )
as OVERTIME
GROUP BY Emp_ID,Name
ORDER BY Sum", Date);
SqlConnection sqlConn = null;
SqlCommand cmd_SignUp;
SqlDataReader dr_SignUp;
try
{
sqlConn = new SqlConnection(databaseConnectionString);
sqlConn.Open();
cmd_SignUp = new SqlCommand(sql_SignUp, sqlConn);
dr_SignUp = cmd_SignUp.ExecuteReader();
while (dr_SignUp.Read())
{
ArrayList arrPhone = new ArrayList();
string sql_Phone = String.Format("SELECT Phone_Number FROM Contact_Details WHERE Emp_ID = {0}", dr_SignUp["Emp_ID"]);
SqlCommand cmd_Phone = new SqlCommand(sql_Phone, sqlConn);
SqlDataReader dr_Phone = cmd_Phone.ExecuteReader();
while (dr_Phone.Read())
{
arrPhone.Add(dr_Phone["Phone_Number"].ToString());
}
//--Retrieving Sectors
ArrayList arrSector = new ArrayList();
string sql_Sector = String.Format(#"SELECT e1.EMP_ID,
( SELECT cast(Sector_ID as varchar(10)) + ';'
FROM Employee_Sector_relationship e2
WHERE e2.Emp_ID = e1.Emp_ID
ORDER BY Sector_ID
FOR XML PATH('') ) AS Sectors
FROM Employee_Sector_Relationship e1
WHERE Emp_ID = {0}
GROUP BY Emp_ID ", dr_SignUp["Emp_ID"]);
SqlCommand cmd_Sector = new SqlCommand(sql_Sector, sqlConn);
SqlDataReader dr_Sector = cmd_Sector.ExecuteReader();
while (dr_Sector.Read())
{
arrSector.Add(dr_Sector["Sectors"].ToString());
}
if (arrSector.Count == 0)
{ arrSector.Add(" "); }
if (arrPhone.Count == 0)
{ arrPhone.Add(" "); }
//--
if (arrPhone.Count == 2)
{
PassedGrid.Rows.Add(dr_SignUp["Emp_ID"].ToString(), dr_SignUp["Name"].ToString(), arrSector[0], dr_SignUp["Sum"], arrPhone[0], arrPhone[1]);
}
else
{
PassedGrid.Rows.Add(dr_SignUp["Emp_ID"].ToString(), dr_SignUp["Name"].ToString(), arrSector[0], dr_SignUp["Sum"], arrPhone[0]);
}
}
}
catch (Exception e)
{
MessageBox.Show("Error found in SignUpControllerDay..." + Environment.NewLine + e.ToString());
}
finally
{
if (sqlConn != null)
{
sqlConn.Close();
}
}
}
Everything works fine.
Now the real problem. I have been informed that the production SQL server for the application to go live is Microsoft SQL server 2000. After doing a bit research, I came to know that Microsoft server 2000 does not support multiple active results sets propery. In short, it does not allow me to use 2 data readers simultaneously.
I need to know how to read the data from 2 different tables, simultaneously, with regards to SQL Server 2000.
Are there any other ways that i can read data as I have mentioned in the code..
Please help..
the application is almost done and is ready to go to production. but MS server 2000 doesnt allow the applcaition to work accordingly...
please help
You can have two active datareaders in Sql Server 2000 by simply creating two connections.
To demonstrate this, I must first berate you for using two very poor practices: dynamic sql and arraylists. Neither have any place in your code. You should also read up on the using construct, though you have my apologies and condolences on "using" and "arraylists" if you're still using .net 1.1.
That said, here's how the code should look:
string sql_Phone = "SELECT Phone_Number FROM Contact_Details WHERE Emp_ID = #EmpID";
using (SqlConnection cn2 = new Sqlconnection(databaseConnectionString))
using (SqlCommand cmd_Phone = new SqlCommand(sql_Phone, cn2))
{
cmd_Phone.Parameters.Add("#EmpID", SqlDbType.Int);
cn2.Open();
while (dr_SignUp.Read())
{
List<string> arrPhone = new List<string>();
cmd_Phone.Parameters[0].Value = dr_SignUp["Emp_ID"];
using (SqlDataReader dr_Phone = cmd_Phone.ExecuteReader())
{
while (dr_Phone.Read())
{
arrPhone.Add(dr_Phone["Phone_Number"].ToString());
}
}
Also, looking at your code I suspect what you really need to do is re-write your sql. You can combine all those into a single query that you just bind directly to the grid.
Sure:
public void SignUpControllerDay()
{
using (var conn = new SqlConnection(ConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT ...";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var phone = reader["Phone_Number"].ToString();
Bar(phone);
}
}
}
}
public void Bar(string phone)
{
using (var conn = new SqlConnection(ConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT ..."; // use phone to prepare statement
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// Fill the grid
}
}
}
}
You could open multiple database connections with 1 reader per connection
You could also add MultipleActiveResultSets=True; to the connection string, even though it's not recommended.
so, it is not possible! as simple as that the only answer!
multiple connection is a workaroud!
one connection can not handle multiple recordsets simultaneously

Categories