c# combine two results from two different database providers - c#

I need to check if something in one table (table 1) was added and if so I need to take some values from this table and insert it in the second table (table 2).
The problem is that the Table 1 is .DBF Provider=VFPOLEDB.1 connected by OleDbConnection and the second Table 2 is MSSQL table connected by SqlConnection.
I want to make something like this:
SELECT column1 FROM Table1 WHERE column1 NOT IN (SELECT column2 FROM Table2)
Is it possible to do this? I can load both tables to the datagridview by doing:
public static DataTable GetDataTableDBF(string strFileName)
{
OleDbConnection conFOX = new OleDbConnection("Provider=VFPOLEDB.1;Data Source=" + Path.GetFullPath(strFileName).Replace(Path.GetFileName(strFileName), "") + ";Exclusive=No");
conFOX.Open();
string strQuery = "SELECT * FROM [" + Path.GetFileName(strFileName) + "]";
OleDbDataAdapter adapter = new OleDbDataAdapter(strQuery, conFOX);
DataSet ds = new DataSet();
adapter.Fill(ds);
return ds.Tables[0];
}
for OleDbConnection and doing:
public static DataTable GetDataTableSQL(string TableName)
{
SqlConnection conSQL = new SqlConnection(connection);
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
conSQL.Open();
string strQuery = "SELECT * FROM " + TableName;
da.SelectCommand = new SqlCommand(strQuery, conSQL);
da.Fill(ds);
return ds.Tables[0];
}
for SqlConnection. Mayby I can do 2 datasets or something like temporary tables from this query? so it will be something like this? :
SELECT dataset1.column1 FROM dataset1 WHERE dataset1.column1 NOT IN (SELECT dataset2.column2 FROM dataset2)

Since both datatables are from different sources you need to fetch both datatables into memory and then use linq to dataset. something like this
var datatable1 = GetDataTableDBF("filename");
var datatable2 = GetDataTableSQL("tablename");
var query = from c in dataset1.AsEnumerable()
where !(from o in dataset2.AsEnumerable()
select o.Field<int>("column2")).Contains(c.Field<int>("column1"))
select c;
var filteredDataTable1 = query.CopyToDataTable();
var resultDataTable = filteredDataTable1.DefaultView.ToTable(false, "column1"); //create new table with only 1 column
dataGridView1.DataSource = resultDataTable;

Related

Output data from DataTables within DataSet

I currently accessing a database using multiple queries and storing the results from the queries into DatatTables. I decided since I'm using multiple DataTables to store them inside a DataSet.
I can see that data is inside the DataTables when I print them out. However when I try to access them from the DataSet to print out the data, I get nothing back; it is empty.
string querytest1 = "SELECT * FROM test1";
string querytest2 = "SELECT * FROM test2";
string querytest3 = "SELECT * FROM test3";
using(OleDbConnection connection = new OleDbConnection(connectionString)){
OleDbCommand commandtest1 = new OleDbCommand(querytest1 , connection);
OleDbCommand commandtest2 = new OleDbCommand(querytest2 , connection);
OleDbCommand commandtest3 = new OleDbCommand(querytest3 , connection);
connection.Open();
DataSet dataSet = new DataSet();
OleDbDataAdapter dataAdaptertest1 = new OleDbDataAdapter(commandResults);
OleDbDataAdapter dataAdaptertest2 = new OleDbDataAdapter(commandResults);
OleDbDataAdapter dataAdaptertest3 = new OleDbDataAdapter(commandProjects);
DataTable dataTabletest1 = new DataTable();
DataTable dataTabletest2 = new DataTable();
DataTable dataTabletest3 = new DataTable();
dataAdaptertest1.Fill(dataTabletest1 );
dataAdaptertest2.Fill(dataTabletest2 );
dataAdaptertest3.Fill(dataTabletest3 );
dataTabletest1 = dataSet.Tables.Add("test1 ");
dataTabletest2 = dataSet.Tables.Add("test2 ");
dataTabletest3 = dataSet.Tables.Add("test3 ");
Console.WriteLine("DataSet has {0} DataTables \n", dataSet.Tables.Count);
foreach (DataTable objDt in dataSet.Tables)
Console.WriteLine("{0}", objDt.TableName);
return dataSet;
Expected behaviour: is to be able to access a DataTable from the DataSet and print out the data.
Example: Print out the contents in Test1
The code is redundant. I just don't know a better way to do this.
You don't need three adapters to fill a DataSet with the results from three commands.
You can simply write:
string query1 = "SELECT * FROM test1";
string query2 = "SELECT * FROM test2";
string query3 = "SELECT * FROM test3";
DataSet dataSet = new DataSet();
using(OleDbConnection connection = new OleDbConnection(connectionString)){
connection.Open();
OleDbCommand cmd = new OleDbCommand(q1, connection);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(ds, "Test1");
cmd.CommandText = q2;
da = new OleDbDataAdapter(cmd);
da.Fill(ds, "Test2");
cmd.CommandText = q3;
da = new OleDbDataAdapter(cmd);
da.Fill(ds, "Test3");
}
Console.WriteLine("DataSet has {0} DataTables \n", ds.Tables.Count);
foreach (DataTable objDt in ds.Tables)
Console.WriteLine("{0}", objDt.TableName);
The trick is filling the same DataSet three times instead of three different DataTables and giving at each fill a different name for each table created.
But, don't you see that dataSet.Tables.Add() call actually creates new DataTable instance, and trying to set its TableName property to "test1 " (btw. take care, space is not allowed in TableName).
That newly created instance(s) are set to properties dataTabletest1...3 - so, you lose access to the original ones, initially populated with data from the database.
You should do something like this:
DataTable dataTabletest1 = dataSet.Tables.Add("Test1");
DataTable dataTabletest2 = dataSet.Tables.Add("Test2");
DataTable dataTabletest3 = dataSet.Tables.Add("Test3");
dataAdaptertest1.Fill(dataTabletest1);
dataAdaptertest2.Fill(dataTabletest2);
dataAdaptertest3.Fill(dataTabletest3);
Please, check: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/dataset-datatable-dataview/adding-a-datatable-to-a-dataset

c# selecting all record with specific data on datatable

I'm planning to select all rows in my datatable that has 'Dog' in column 2 without using keyword "WHERE" on my query. My guess is to try using DataRow and foreach but I'm not sure where to start. I filled my datatable with records coming from my database and this is what I've done so far.
using(MySqlConnection con = new MySqlConnection(constring))
{
MySqlDataAdapter adp = new MySqlDataAdapter("SELECT * FROM table1",con);
DataTable dt = new DataTable();
adp.Fill(dt);
adp.Dispose();
}
This is what my datatable looks like:
Column1 Column2 Column3
1 Dog Labrador
2 Dog Chowchow
3 Cat Persian
4 Cat Stubby
5 Dog German Shepherd
You can filter records when populating table using data adapter by modifying select query:
SELECT * FROM table1 WHERE Column2='Dog'
and second approach if you need to filter later then use this approach - Creating a DataTable From a Query (LINQ to DataSet):
List<DataRow> result = dt.AsEnumerable().Where(row=> row.Field<string>("Column2") = "Dog").ToList();
You can filter records by using DataView and use the RowFilter Property as below:
// Create a DataView
DataView dv = new DataView(dt);
// Filter by an expression.
dv.RowFilter = "Column2 = 'Dog'";
DataTable newTable = view.ToTable();
References:
Creating a DataTable from a DataView
You are looking for a SQL WHERE clause. Always use SqlParameter or similar to insert variables into a query (prevents potential SQL injection attacks if parameter value is user provided).
string genusInput = "Dog"; // might be provided by user input later on
DataTable result = new DataTable();
using (MySqlConnection con = new MySqlConnection(constring)) {
const string query = "SELECT * FROM table1 WHERE Column2 = #genus";
var adp = new MySqlDataAdapter(query, con);
adp.SelectCommand.Parameters.AddWithValue("#genus", genusInput);
adp.Fill(result);
adp.Dispose();
}
Use where to distinguish:
using(MySqlConnection con = new MySqlConnection(constring))
{
MySqlDataAdapter adp = new MySqlDataAdapter("SELECT * FROM table1,con);
DataTable dt = new DataTable();
adp.Fill(dt);
IEnumerable<DataRow> query = adp.Where(x => x.Column2 == 'dog').ToList();
DataTable filteredRows = query.CopyToDataTable<DataRow>();
adp.Dispose();
}
using(MySqlConnection con = new MySqlConnection(constring))
{
MySqlDataAdapter adp = new MySqlDataAdapter("SELECT * FROM table1",con);
DataTable dt = new DataTable();
adp.Fill(dt);
adp.Dispose();
DataRow[] dr=dt.select(“Column2=‘Dog’”);
}
https://msdn.microsoft.com/en-us/library/det4aw50(v=vs.110).aspx
Create where statement in your query as below sample
MySqlDataAdapter adp = new MySqlDataAdapter("SELECT * FROM table1 WHERE Column2='Dog'",con);

Keep adding query results to datatable

I have a dataset which contains two tables. Table[0] gets filled with multiple rows. I then need to iterate those rows and for each row run another query and fill those results to Table[1]. What is the correct way to fill a dataset with multiple rows within a loop? Abbreviated code sample of where I am:
DataSet ds = new DataSet();
sql = myquery1;
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
da.Fill(ds, "Products");
foreach (DataRow dr in ds.Tables[0].Rows)
{
productID = ds.Tables[0].Rows[0]["ProductID"].ToString();
if (productID != String.Empty)
{
sql = String.Empty;
sql = myquery2 where productID = 'xxxxx'
da = new SqlDataAdapter(sql, conn);
da.Fill(ds, "ProductProperties");
}
}
This fills the "ProductProperties" datatable on the first loop but doesn't add future results. What's the right way to keep adding multiple result sets to the datatable?
You're going about this the wrong way. You only need one query to populate the child table. E.g.
Dim ds As New DataSet
Using connection As New SqlConnection("connection string here"),
parentAdapter As New SqlDataAdapter("SELECT * FROM ParentTable",
connection),
childAdapter As New SqlDataAdapter("SELECT * FROM ChildTable WHERE ParentID IN (SELECT ParentID FROM ParentTable)",
connection)
connection.Open()
parentAdapter.Fill(ds, "Parent")
parentAdapter.Fill(ds, "Child")
End Using
All you need to do is duplicate the parent query as the subquery for the child table. You can even put both queries inside one data adapter if you want. The point is that there's no need to loop through the parent records and execute a separate query for each one.
You query should return two record sets
SELECT ProductId, Name
FROM Products
SELECT ProductId, Property1, Property2
FROM ProductProperties
Then you can read the data from the above query to a DataSet as follows. So you will get two tables in the DataSet with the results from the two records sets from the above query
using (SqlConnection con = new System.Data.SqlClient.SqlConnection(connString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "query";
cmd.Connection = con;
con.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
adapter.Fill(ds);
con.Close();
}
}

Apply a TableStyle to a QueryTable

I can use a query table:
var sheet = (_excel.ActiveSheet as Excel.Worksheet);
var rng = sheet.Range("A1");
var qt = sheet.QueryTables.Add("ODBC;...", rng, "SELECT * FROM myTable");
qt.Refresh();
and this will import the data correctly (e.g. dates actually display as dates etc...). But when I try and access the ListObject to apply a TableStyle I get an exception.
Now if I add a list object like:
var sheet = (_excel.ActiveSheet as Excel.Worksheet);
var qt = sheet.ListObjects.Add(
Excel.Enums.XlListObjectSourceType.xlSrcQuery,
"ODBC;...",
null,
Excel.Enums.XlYesNoGuess.xlNo,
rng,
"TableStyleMedium9").QueryTable;
qt.CommandType = Excel.Enums.XlCmdType.xlCmdSql;
qt.CommandText = "SELECT * FROM myTable";
qt.Refresh();
The the dates in the query display as decimal numbers and not dates...
I could just format the columns afterwards, but the problem is that I won't actually know the query that is being run as the user types this at runtime, so I would prefer to get Excel to do this.
So essentially, what I want, is to use the first bit of code and apply a TableStyle to it.
Can anyone help?
This doesn't do coloring, but it does organize the data into a datatable, and when you're debugging with breakpoints and mouse over the datatable after its been filled you can see all the data organized into columns. What you can then do with the datatable is bind it to a datagrid view on your win forms element.
I have this DataTable DataTable = new DataTable(); as a global field at the top.
OleDbConnection conn = new OleDbConnection();
//This is making a connection to the excel file, don't worry about this I think you did it differently.
conn.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + stringFileName + ";" + "Extended Properties=\"Excel 12.0;HDR=Yes;\""; OleDbCommand cmd = new OleDbCommand
("SELECT * FROM [" + sheetFromTo + "]", conn);
DataSet dataSet1 = new DataSet();
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(cmd);
try
{
conn.Open();//opens connection
dataSet1.Clear();//empties, incase they refill it later
dataAdapter.SelectCommand = cmd;//calls the cmd up above
dataAdapter.Fill(dataSet1);//fills the dataset
dataGridView1.DataSource = dataSet1.Tables[0];//puts the dataset in the dataGridview
//important** creates a datatable from the dataset, most of our work with the server is with this datatable
DataTable dataTable = dataSet1.Tables[0];
DataTable = dataTable;
}
catch (Exception ex)
{
}
finally
{
conn.Close();
}

Loop through ado.net sql select to add more rows to datatable

I currently have a working query for the first element in the array of ID's as seen below. What I need to do is add a for loop so I rerun the query for every element in the array and add each new row to the datatable but I am not sure how I do this? Unless there is a way I can include all ID's of my array in the where clause so I retrieve all rows through first run.
PID[] is a string array and could have anywhere from 1 to 5 elements that are random ID's.
Any help would be appreciated!
for loop here?
string firstQuery = "select * from Property p " +
"where p.id in (#pID)";
connString.Open();
SqlCommand selectAll = new SqlCommand(firstQuery, connString);
selectAll.Parameters.AddWithValue("#pID", PID[0]);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = selectAll;
DataSet ds = new DataSet();
adapter.Fill(ds);
connString.Close();
DataTable table = ds.Tables[0];
Yes you can include all ids in one parameter and get results that match them:
var parameters = new string[PID.Length];
var selectAll = new SqlCommand();
for (int i = 0; i < PID.Length; i++)
{
parameters[i] = string.Format("#Age{0}", i);
selectAll .Parameters.AddWithValue(parameters[i], PID[i]);
}
selectAll.CommandText = string.Format("SELECT * from Property p WHERE p.id IN ({0})", string.Join(", ", parameters));
selectAll.Connection = connString;
connString.Open();
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = selectAll;
DataSet ds = new DataSet();
adapter.Fill(ds);
connString.Close();
DataTable table = ds.Tables[0];

Categories