Insert rows to DataTable from SQL table - c#

I have a Datatable in my C# program that I would like to INSERT rows from a temp table in SQL Server. The dataAdapter.FILL() method writes over the whole datatable. I need to keep the records that are in the DataTable and add records that exist in the temp table back into my DataTable.
I do not see a DA method for that, they all seem to go back to the SQL Server table except FILL. Is this possible?

How about Merging your DataTables
DataTable dttemp = new DataTable();
dataAdapter.Fill(dtTemp);
originaldatatable.Merge(dtTemp);

// Now, open a database connection using the Microsoft.Jet.OLEDB provider.
// The "using" statement ensures that the connection is closed no matter what.
using (var connection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data source=Northwind.mdb"))
{
connection.Open();
// Create an OleDbDataAdapter and provide it with an INSERT command.
var adapter = new OleDbDataAdapter();
adapter.InsertCommand = new OleDbCommand("INSERT INTO Shippers (CompanyName, Phone) VALUES (#CompanyName , #Phone)", connection);
adapter.InsertCommand.Parameters.Add("CompanyName", OleDbType.VarChar, 40, "CompanyName");
adapter.InsertCommand.Parameters.Add("Phone", OleDbType.VarChar, 24, "Phone");
adapter.Update(data);
}

Related

Execute query and populate the same in datagrid Box

I have a winform app connected to access database as data source ,
but in access i was using this below SQL to generate a query table called trend:
TRANSFORM Count(Complaint_Number) AS [Total Numbers]
SELECT Nature_of_problem, Count(Complaint_Number) AS [Total Numbers of Issues]
FROM master_table
GROUP BY Nature_of_problem
PIVOT Format(Complaint_Received_On,"mmm") In ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
But i do not know how execute this & populate the same in datagrid box on form load event(dataset:CSCdataset) , please help me.
I guess you can find more information on your question here:
How to query MS Access database with C# application?
This post refers to the documentation: https://learn.microsoft.com/en-us/previous-versions/dotnet/articles/ms971485(v=msdn.10)?redirectedfrom=MSDN
In my winform-app, I use an SQL Server. It is probably somehow the same procedure for an Access database:
using System.Data.SqlClient;
//open connection
//cnnString = $#"Data Source=<yourServer>;Integrated Security=SSPI;Persist Security Info=True;Initial Catalog=<yourDatabase>
SqlConnection cnn = new SqlConnection(#cnnString);
cnn.Open();
//execute query
string exec = $#"<your query>";
DataSet dataSet = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(exec, cnn);
adapter.Fill(dataSet); //fill dataset
cnn.Dispose();
//read dataset
dataSet.Tables[0].Rows ...
You can enhance this code by putting cnn into a using statement, like so:
using (SqlConnection connection = new SqlConnection(
connectionString)) {
try {
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex){
//log and/or rethrow or ignore
}
}
Source: The C# using statement, SQL, and SqlConnection
To bind a DataTable to a DataGridView, just assign the DataTable to the DataSource Property of the DataGridView, like so:
dataGridView.DataSource = yourDataTable;
I hope I helped you a little with my answer.
Cheers

c# How to clear oledbconnection cache, multiple excel queries erroring out

Sorry for the vague title but I'm not sure how best to word it.
Basically, the issue that I'm having is that I initially was using an oledbconnection in C# to initiate a connection to a spreadsheet, query it, and load the results into a .net datatable. Unfortunately, it maxes out at 255 fields which I have around 600.
So, what I did instead was I created a dataset and tried to load 4 separate data tables with separate queries. Now for some reason, what's crazy to me is, if I load lets say, the first data table with 190 fields, and then I go on to query the spreadsheet again, if I go over that 250 mark (which I'd have 60 left), I get the following error:
An exception of type 'System.Data.OleDb.OleDbException' occurred in System.Data.dll but was not handled in user code
Additional information: No value given for one or more required parameters.
If I reduce the amount of fields in the second table to equal less than 250 though, it works. Anyway, is there a way that I can somehow clear the cache of the oledbconnection to somehow drop the first 190 fields or whatever is holding the result of the excel query so I can move on to the next? I tried doing a data adapter dispose but that didn't work, same issue. If I do a connection.dispose, I have to re-initialize the connection anyway. Is there a way I can still do this without having to drop the connection? Code below:
OleDbConnection cnn = new OleDbConnection(Settings.ExcelCN);
OleDbCommand fillT1 = new OleDbCommand(Settings.Excel_Proj_Select_1, cnn);
OleDbCommand fillT2 = new OleDbCommand(Settings.Excel_Proj_Select_2, cnn);
OleDbCommand fillT3 = new OleDbCommand(Settings.Excel_Proj_Select_3, cnn);
OleDbCommand fillT4 = new OleDbCommand(Settings.Excel_Proj_Select_4, cnn);
OleDbCommand updateCnt = new OleDbCommand(Settings.Excel_Update_Count_Select, cnn);
cnn.Open();
OleDbDataAdapter adp1 = new OleDbDataAdapter(fillT1);
OleDbDataAdapter adp2 = new OleDbDataAdapter(fillT2);
OleDbDataAdapter adp3 = new OleDbDataAdapter(fillT3);
OleDbDataAdapter adp4 = new OleDbDataAdapter(fillT4);
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
DataTable dt3 = new DataTable();
DataTable dt4 = new DataTable();
DataSet ds1 = new DataSet();
adp1.Fill(dt1);
ds1.Tables.Add(dt1);
adp2.Fill(dt2);
ds1.Tables.Add(dt2);
adp3.Fill(dt3);
ds1.Tables.Add(dt3);
adp4.Fill(dt4);
ds1.Tables.Add(dt4);
int rowcount = updateCnt.ExecuteNonQuery();
cnn.Close();

Writing to SQL Server Database

I am having trouble writing my datagrid changes to the database, i am trying to type in the changes on the grid and then when Button_Add_Car is pressed i execute this code and write changes to the database but nothing is being written to the database.
private void Button_Add_Car(object sender, RoutedEventArgs e)
{
SqlConnection cn = new SqlConnection();
DataSet dt = new DataSet();
SqlDataAdapter da;
SqlCommandBuilder cmdBuilder;
cn.ConnectionString = (String.Format("Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}", SQLFunctions.connectSQL.SQLSERVER_ID, SQLFunctions.connectSQL.SQLDatabaseName, SQLFunctions.connectSQL.SQLServerLoginName, SQLFunctions.connectSQL.SQLServerPassword));
cn.Open();
da = new SqlDataAdapter("SELECT * FROM Cars", cn);
cmdBuilder = new SqlCommandBuilder(da);
da.Fill(dt);
da.Update(dt);
cn.Close();
}
Am i on the right track using this method?
Am i using the correct SQL Query? I am confused between the SELECT/INSERT as i have found examples where people are using both to achieve what i want to do. Surely i should be using the INSERT statement.
I made my own custom SQL Command to manually insert into the database so it is in fact working:
SQLCmd("INSERT INTO Cars (Date, Time) VALUES(2014-10-10, '12:00:00')");
EDIT 1:
Thanks to marc_s i managed to achieve some sort of inserting but i believe i need to modify the value section to be inside an IF Statement which will check if it is a null or not and change value back to cr.Date and cr.Time as i am making use of a list. I am unsure of how to utilize the if statement in this way because it is currently entering blank rows, although its a step in the right direction:
CarRecord cr = new CarRecord();
carRecords.Add(cr);
SqlConnection con = new SqlConnection(String.Format(#"Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}", SQLFunctions.connectSQL.SQLSERVER_ID, SQLFunctions.connectSQL.SQLDatabaseName, SQLFunctions.connectSQL.SQLServerLoginName, SQLFunctions.connectSQL.SQLServerPassword));
con.Open();
SqlCommand comm = new SqlCommand("INSERT INTO Cars VALUES (#Date, #Time)", con);
SqlDataAdapter da = new SqlDataAdapter(comm);
da.SelectCommand.Parameters.Add(new SqlParameter("#Date", SqlDbType.NVarChar)).Value = DBNull.Value;
da.SelectCommand.Parameters.Add(new SqlParameter("#Time", SqlDbType.NVarChar)).Value = DBNull.Value;
da.SelectCommand.ExecuteNonQuery();
DataTable dt = new DataTable();
SqlCommandBuilder builder = new SqlCommandBuilder(da);
da.Update(dt);
con.Close();
lets take your first code example.
take a look at the last 3 lines, first thing you do is to copy data from the table Cars and store that into the DataSet named dt.
then immediately after you store this dataset back into the database, without actually doing any changes.
if dot net is smart enough it wont do anything, since you didn't change anything between the fill and the update call.
what you probably should be doing is get the dataset from the datagrid or similar and store that one instead.
or do as you have started on in your second example of when you identity that a row is updated take the data from that row and construct an insert (or update) query to the database.

Giving table friendly name in SQL query using MS SQL server

I am using ADO.NET to execute store procedure. The store procedure is having multiple select statement. When I access DataSet, the tables are named as Table1, Table2 and so on. I want to give user friend name to each of these table. I do not want to use Table variable or temp tables in my SQL query. DO I have any other alternatives?
I am using following code to get the dataset
SqlCommand cmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
try
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["connString"].ConnectionString;
con.Open();
cmd = new SqlCommand("sp_GetData", con);
cmd.Parameters.Add(new SqlParameter("#ParamOne", param));
cmd.CommandType = CommandType.StoredProcedure;
da.SelectCommand = cmd;
da.Fill(ds);
}
I dont want to do this either
da.TableMappings.Add("Table", "MyTable1");
da.TableMappings.Add("Table1", "MyTable2");
da.TableMappings.Add("Table2", "MyTable3");
or this
ds.Tables[0].TableName = "NametbA";
ds.Tables[1].TableName = "NametbB";
Preferably I want to specify the name in the SQL query. The reason I want to use this approach is because, I will pass this dataset as it to a function which will write the table name into a file.
Please provide your suggestions.
Thank you
It is unfortunately not possible to set it automatically. You will have to provide it to the code somehow.
One option would be to change the structure of your results to have twice as many result sets where the odd one is the name and the even is the data:
-- Table name
SELECT 'nameoftable' AS TableName
-- Data
SELECT * FROM ...
c# code (consider it to be psudo code):
myDataSet.Tables[1].TableName = myDataSet.Tables[0]["TableName"].ToString();
Table names in the ADO.Net dataset object are entirely .Net, C# (or vb.net) specific. They have nothing to do with the table names in the SQL query or in the database. Change them in your C# code, by simply writing
myDataSet.Tables[0].TableName 'WhateverYouWant";

Using temporary table in c#

I read an excel sheet into a datagrid.From there , I have managed to read the grid's rows into a DataTable object.The DataTable object has data because when I make equal a grid's datasource to that table object , the grid is populated.
My Problem : I want to use the table object and manipulate its values using SQL server,(i.e. I want to store it as a temporary table and manipulate it using SQL queries from within C# code and , I want it to return a different result inte a grid.(I don't know how to work with temporary tables in C#)
Here's code to execute when clicking button....
SqlConnection conn = new SqlConnection("server = localhost;integrated security = SSPI");
//is connection string incorrect?
SqlCommand cmd = new SqlCommand();
//!!The method ConvertFPSheetDataTable Returns a DataTable object//
cmd.Parameters.AddWithValue("#table",ConvertFPSheetDataTable(12,false,fpSpread2_Sheet1));
//I am trying to create temporary table
//Here , I do a query
cmd.CommandText = "Select col1,col2,SUM(col7) From #table group by col1,col2 Drop #table";
SqlDataAdapter da = new SqlDataAdapter(cmd.CommandText,conn);
DataTable dt = new DataTable();
da.Fill(dt); ***// I get an error here 'Invalid object name '#table'.'***
fpDataSet_Sheet1.DataSource = dt;
//**NOTE:** fpDataSet_Sheet1 is the grid control
Change your temp table from #table to ##table in both places.
Using ## means a global temp table that stays around. You'll need to Drop it after you have completed your task.
Command = " Drop Table ##table"
Putting the data into a database will take time - since you already have it in memory, perhaps LINQ-to-Objects (with DataSetExtensions) is your friend? Replace <int> etc with the correct types...
var query = from row in table.Rows.Cast<DataRow>()
group row by new
{
Col1 = row.Field<int>(1),
Col2 = row.Field<int>(2)
} into grp
select new
{
Col1 = grp.Key.Col1,
Col2 = grp.Key.Col2,
SumCol7 = grp.Sum(x => x.Field<int>(7))
};
foreach (var item in query)
{
Console.WriteLine("{0},{1}: {2}",
item.Col1, item.Col2, item.SumCol7);
}
I don't think you can make a temp table in SQL the way you are thinking, since it only exists within the scope of the query/stored procedure that creates it.
If the spreadsheet is a standard format - meaning you know the columns and they are always the same, you would want to create a Table in SQL to put this file into. There is a very fast way to do this called SqlBulkCopy
// Load the reports in bulk
SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString);
// Map the columns
foreach(DataColumn col in dataTable.Columns)
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
bulkCopy.DestinationTableName = "SQLTempTable";
bulkCopy.WriteToServer(dataTable);
But, if I'm understanding your problem correctly, you don't need to use SQL server to modify the data in the DataTable. You c an use the JET engine to grab the data for you.
// For CSV
connStr = string.Format("Provider=Microsoft.JET.OLEDB.4.0;Data Source={0};Extended Properties='Text;HDR=Yes;FMT=Delimited;IMEX=1'", Folder);
cmdStr = string.Format("SELECT * FROM [{0}]", FileName);
// For XLS
connStr = string.Format("Provider=Microsoft.JET.OLEDB.4.0;Data Source={0}{1};Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'", Folder, FileName);
cmdStr = "select * from [Sheet1$]";
OleDbConnection oConn = new OleDbConnection(connStr);
OleDbCommand cmd = new OleDbCommand(cmdStr, oConn);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
oConn.Open();
da.Fill(dataTable);
oConn.Close();
Also, in your code you ask if your connection string is correct. I don't think it is (but I could be wrong). If yours isn't working try this.
connectionString="Data Source=localhost\<instance>;database=<yourDataBase>;Integrated Security=SSPI" providerName="System.Data.SqlClient"
Pardon me, if I have not understood what you exactly want.
If you want to perform SQL query on excel sheet, you could do it directly.
Alternatively, you can use SQL Server to query excel (OPENROWSET or a function which I dont remember right away). Using this, you can join a sql server table with excel sheet
Marc's suggestion is one more way to look at it.
Perhaps you could use a DataView. You create that from a DataTable, which you already have.
dv = new DataView(dataTableName);
Then, you can filter (apply a SQL WHERE clause) or sort the data using the DataView's methods. You can also use Find to find a matching row, or FindRows to find all matching rows.
Some filters:
dv.RowFilter = "Country = 'USA'";
dv.RowFilter = "EmployeeID >5 AND Birthdate < #1/31/82#"
dv.RowFilter = "Description LIKE '*product*'"
dv.RowFilter = "employeeID IN (2,4,5)"
Sorting:
dv.Sort = "City"
Finding a row: Find the customer named "John Smith".
vals(0)= "John"
vals(1) = "Smith"
i = dv.Find(vals)
where i is the index of the row containing the customer.
Once you've applied these to the DataView, you can bind your grid to the DataView.
Change the command text from
Select col1,col2,SUM(col7) From #table group by col1,col2
to
Select col1,col2,SUM(col7) From ##table group by col1,col2

Categories

Resources