I am retrieving data from a SQL table so I can display the result on the page as a HTML table. Later I need to be able to save that table as a CSV file.
So far I have figured out how to retrieve the data and fill them in a dataset for display purpose (which is working perfectly)...
string selectQuery = "SELECT Name, ProductNumber, ListPrice FROM Poduction.Product";
// Establish the connection to the SQL database
SqlConnection conn = ConnectionManager.GetConnection();
conn.Open();
// Connect to the SQL database using the above query to get all the data from table.
SqlDataAdapter myCommand = new SqlDataAdapter(selectQuery, conn);
// Create and fill a DataSet.
DataSet ds = new DataSet();
myCommand.Fill(ds);
and how to save them in a CSV file with the help of following code from: http://www.evontech.com/login/topic/1983.html
private void exportDataTableToCsv(DataTable formattedDataTable, string filename)
{
DataTable toExcel = formattedDataTable.Copy();
HttpContext context = HttpContext.Current;
context.Response.Clear();
foreach (DataColumn column in toExcel.Columns)
{
context.Response.Write(column.ColumnName + ",");
}
context.Response.Write(Environment.NewLine);
foreach (DataRow row in toExcel.Rows)
{
for (int i = 0; i < toExcel.Columns.Count; i++)
{
context.Response.Write(row.ToString().Replace(",", string.Empty) + ",");
}
context.Response.Write(Environment.NewLine);
}
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + filename + ".csv");
context.Response.End();
}
Now my problem is how do I convert this DataSet to DataTable? I have tried the way described here with NO luck: http://www.ezineasp.net/post/ASP-Net-C-sharp-Convert-DataSet-to-DataTable.aspx
Can anyone help me?
A DataSet already contains DataTables. You can just use:
DataTable firstTable = dataSet.Tables[0];
or by name:
DataTable customerTable = dataSet.Tables["Customer"];
Note that you should have using statements for your SQL code, to ensure the connection is disposed properly:
using (SqlConnection conn = ...)
{
// Code here...
}
DataSet is collection of DataTables.... you can get the datatable from DataSet as below.
//here ds is dataset
DatTable dt = ds.Table[0]; /// table of dataset
Here is my solution:
DataTable datatable = (DataTable)dataset.datatablename;
Related
I wrote some methods which are supposed to fetch a DataTable for each WorkSheet in a Excel file:
Step 1 is to get the names of all sheets included in a .xlsx file:
private static List<string> GetSheetNames(string filePath)
{
List<string> sheetNames = new List<string>();
DataTable dt = null;
try
{
OleDbConnection connection = new OleDbConnection("provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + filePath + "';Extended Properties='Excel 12.0 Xml;HDR=YES;'");
connection.Open();
dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
return null;
}
// Add the sheet name to the string array.
foreach (DataRow row in dt.Rows)
{
sheetNames.Add(row["TABLE_NAME"].ToString());
}
}catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
return sheetNames;
}
Step 2 is to read every sheet and return an according DataTable:
private static DataTable ReadExcelSheet(string filePath,string sheetName)
{
DataTable table = new DataTable();
ValidateSheetName(ref sheetName);
try
{
OleDbConnection connection;
DataSet DtSet;
OleDbDataAdapter cmd;
connection = new OleDbConnection("provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + filePath + "';Extended Properties='Excel 12.0 Xml;HDR=YES;'");
cmd = new OleDbDataAdapter("select * from ["+sheetName+"]", connection);
cmd.TableMappings.Add("Table", sheetName.Replace("$",string.Empty));
DtSet = new DataSet();
cmd.Fill(DtSet);
table = DtSet.Tables[0];
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return table;
}
Both methods are called from this last method which returns a List<DataTable>:
private static List<DataTable> ConvertExcelToTables(string filePath)
{
List<string> sheetNames = GetSheetNames(filePath);
List<DataTable> tableList = new List<DataTable>();
foreach(string sheetName in sheetNames)
{
tableList.Add(ReadExcelSheet(filePath,sheetName));
}
return tableList;
}
There is also a little helper method which should be irrelevant for the question:
private static void ValidateSheetName(ref string sheetName)
{
sheetName = sheetName.EndsWith("$") ? sheetName : sheetName + "$";
}
If I take one sheet from a example file it looks like this:
Now no matter if I just look into the DataTable while debugging or if I bind it as a DataSource of a DataGridView the result looks a little weird:
My guess is that this might have to do with Excel sheets beginning counting with 1 not with 0. But even if this is the case I can't really think of a solution. Or did I miss something. Actually this is a pity because this seems to be a clean solution imo.
No, the problem is caused by
HDR=YES;
in your connection string.
Change it to
HDR=NO;
HDR=YES means that the first line of your Excel sheets is assumed to contain the fields' names of your table. But this is not the case with the sheet shown as an example. Indeed the OleDb provider cannot determine the name of the second column (it's blank) and thus it assigns the default value (the letter F followed by the progressive number of the column)
You could find a lot of examples and explanations about connectionstrings for excel at connectionstrings.com
I have excel file and loaded in c# windows applciaction.
I want to change the value in excel cell e.g change value in cell a10 and save the file.
The excel file contains multiple sheets.
Any help in this regard?
var ds = new DataSet();
ds = Parse(fileName);
static DataSet Parse(string fileName)
{
string connectionString = string.Format("provider=Microsoft.Jet.OLEDB.4.0; data source={0};Extended Properties=Excel 8.0;", fileName);
DataSet data = new DataSet();
foreach (var sheetName in GetExcelSheetNames(connectionString))
{
using (OleDbConnection con = new OleDbConnection(connectionString))
{
var dataTable = new DataTable();
string query = string.Format("SELECT * FROM [{0}]", sheetName);
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
adapter.Fill(dataTable);
data.Tables.Add(dataTable);
}
}
return data;
}
static string[] GetExcelSheetNames(string connectionString)
{
OleDbConnection con = null;
DataTable dt = null;
con = new OleDbConnection(connectionString);
con.Open();
dt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
return null;
}
String[] excelSheetNames = new String[dt.Rows.Count];
int i = 0;
foreach (DataRow row in dt.Rows)
{
excelSheetNames[i] = row["TABLE_NAME"].ToString();
i++;
}
return excelSheetNames;
}
}
To specify that your sheet has a header row or not, modify the connection string to specify the HDR value. Refer to http://www.connectionstrings.com/excel/ for more information.
If your sheet has a header row, you can refer the columns by the header.
If your sheet does not have a header row use F1, F2, F3.... Fn where F1 is the first selected column. If you don't specify where to start, then column A, B, C correspond to F1, F2, F3 etc.
e.g.
SELECT * FROM [Sheet1$] <-- Column A=F1, B=F2 etc.
SELECT * FROM [Sheet1$B1:Z100] <-- Column B=F1, C=F2 etc.
Now once you know how to refer to the columns, rest should be easy. Create an OledbCommand object and execute your command.
UPDATE [Sheet1$A1:A1] SET F1='TestValue1' <-- trick to update only one cell
UPDATE [Sheet1$] SET F1='TestValue1', F2 = 'some value 2' WHERE WhateverCondition
I haven't ever tried with Datasets and DataAdapters with excel oledb, but logically that should work too because in the end they all drill down to Command object.
For example I have this table
EmployeeName EmpoyeeID
John Mark 60001
Bent Ting 60002
Don Park 60003
How I can show the EmployeeID to have a leading asterisk in data table?
Sample: *60001 *60002 *60003
public DataTable ListOfEmployee()
{
DataSet ds = null;
SqlDataAdapter adapter;
try
{
using (SqlConnection myDatabaseConnection = new SqlConnection(myConnectionString.ConnectionString))
{
myDatabaseConnection.Open();
using (SqlCommand mySqlCommand = new SqlCommand("Select * Employee", myDatabaseConnection))
{
ds = new DataSet();
adapter = new SqlDataAdapter(mySqlCommand);
adapter.Fill(ds, "Users");
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return ds.Tables[0];
}
I need to show the dataTable in the crystal report with a leading asterisk in the employee ID
public void Employees()
{
ReportDocument rptDoc = new ReportDocument();
Employees ds = new Employees(); // .xsd file name
DataTable dt = new DataTable();
// Just set the name of data table
dt.TableName = "Employees";
dt = ListOfEmployee(); //This function is located below this function
ds.Tables[0].Merge(dt);
string strReportName = "Employees.rpt";
string strPath = Application.StartupPath + "\\Reports\\" + strReportName;
// Your .rpt file path will be below
rptDoc.Load(strPath);
//set dataset to the report viewer.
rptDoc.SetDataSource(ds);
ReportViewer newReportViewer = new ReportViewer();
newReportViewer.setReport(rptDoc);
newReportViewer.Show();
}
the easiest not the best way to do is to get the data in that format, if and only if it is not meant to be used anywhere else. You can do this in your query
Select '*'+id,col1,col2,col3 from employee
Though the best way is to modify the column value when you consume it. But obviously that is more headache than adding simply in the query.
Add it into the Crystal report itself.
Something like -
"*" & {tblTable.FieldName}
(Although I can't remember the syntax for Crystal reports, sorry!)
Not tested, but replacing the return statement at the end of your function with the following code should work:
DataTable table = ds.Tables[0];
DataTable clonedTable = table.Clone();
clonedTable.Columns["EmployeeID"].DataType = typeof(String);
foreach (DataRow row in table.Rows)
{
clonedTable.ImportRow(row);
}
foreach (DataRow row in clonedTable.Rows)
{
row["EmployeeID"] = "*" + row["EmployeeID"].ToString();
}
return clonedTable;
However, as others have said, I would recommend adding the asterick somewhere down the line when the data is read rather than to the table itself.
i want to extract my table names and save it into variables this is my cod that return 3 answer:student, teacher and score. how can i change it to save these tree table name to 3 variable. thank you.
try
{
SqlDataReader myreader = null;
SqlCommand mycommand = new SqlCommand("select * FROM information_schema.tables WHERE table_type = 'BASE TABLE'", myconnect);
myreader = mycommand.ExecuteReader();
while (myreader.Read())
{
Console.WriteLine(myreader[2].ToString());
}
}
A simple builtin way is using Connection.GetSchema:
using (var con = new System.Data.SqlClient.SqlConnection(conStr))
{
con.Open();
DataTable schemaTable = con.GetSchema("Tables");
IList<string> allTableNames = schemaTable.AsEnumerable()
.Where(r => r.Field<string>("TABLE_TYPE") == "BASE TABLE")
.Select(r => r.Field<string>("TABLE_NAME"))
.ToList();
}
Now you have a List<string> with all table names which you can access via indexer or in a loop or create a comma separated list with string.Join:
string tNames = string.Join(",", allTableNames);
Console.Write("all tables in the given database: " + tNames);
You can use this :
string tableName ="" ; // Variable to stroe the table names
string connectionString = ""; //Your connectionstring
// get records from the table
string commandString =""; //Your query
// create the data set command object
// and the DataSet
SqlDataAdapter DataAdapter =new SqlDataAdapter(commandString, connectionString);
DataSet DataSet = new DataSet( );
// fill the DataSet object
DataAdapter.Fill(DataSet, "Customers");
// Get the one table from the DataSet
DataTable dataTable = DataSet.Tables[0];
// for each row in the table, display the info
foreach (DataRow dataRow in dataTable.Rows)
{
tableName = dataRow[0].tostring();
//...
}
if you want to save the result for future user or a different session then you can use any of the following to methods
first one
use the "insert" query to save the result one by one in the a different table that you would create specially for saving the data
you can put the insert command/statement directly into the for loop
second method
use the xml to store the value very simple and memory friendly
I Have modified #Doctor code to use ArrayList to store number of table name in single variables.
ArrayList alTableName = new ArrayList(); // Variable to stroe the table names
string connectionString = ""; //Your connectionstring
// get records from the table
string commandString =""; //Your query
// create the data set command object
// and the DataSet
SqlDataAdapter DataAdapter =new SqlDataAdapter(commandString, connectionString);
DataSet DataSet = new DataSet( );
// fill the DataSet object
DataAdapter.Fill(DataSet, "Customers");
// Get the one table from the DataSet
DataTable dataTable = DataSet.Tables[0];
// for each row in the table, display the info
foreach (DataRow dataRow in dataTable.Rows)
{
alTableName.Add(dataRow[0].tostring());
//...
}
I have an Excel spreadsheet that will sit out on a network share drive. It needs to be accessed by my Winforms C# 3.0 application (many users could be using the app and hitting this spreadsheet at the same time). There is a lot of data on one worksheet. This data is broken out into areas that I have named as ranges. I need to be able to access these ranges individually, return each range as a dataset, and then bind it to a grid.
I have found examples that use OLE and have got these to work. However, I have seen some warnings about using this method, plus at work we have been using Microsoft.Office.Interop.Excel as the standard thus far. I don't really want to stray from this unless I have to. Our users will be using Office 2003 on up as far as I know.
I can get the range I need with the following code:
MyDataRange = (Microsoft.Office.Interop.Excel.Range)
MyWorkSheet.get_Range("MyExcelRange", Type.Missing);
The OLE way was nice as it would take my first row and turn those into columns. My ranges (12 total) are for the most part different from each other in number of columns. Didn't know if this info would affect any recommendations.
Is there any way to use Interop and get the returned range back into a dataset?
I don't know about a built-in function, but it shouldn't be difficult to write it yourself. Pseudocode:
DataTable MakeTableFromRange(Range range)
{
table = new DataTable
for every column in range
{
add new column to table
}
for every row in range
{
add new datarow to table
for every column in range
{
table.cells[column, row].value = range[column, row].value
}
}
return table
}
I don't know what type of data you have.But for an excel data like shown in this link http://www.freeimagehosting.net/image.php?f8d4ef4173.png, you can use the following code to load into data table.
private void Form1_Load(object sender, EventArgs e)
{
try
{
DataTable sheetTable = loadSingleSheet(#"C:\excelFile.xls", "Sheet1$");
dataGridView1.DataSource = sheetTable;
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message, "");
}
}
private OleDbConnection returnConnection(string fileName)
{
return new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileName + "; Jet OLEDB:Engine Type=5;Extended Properties=\"Excel 8.0;\"");
}
private DataTable loadSingleSheet(string fileName, string sheetName)
{
DataTable sheetData = new DataTable();
using (OleDbConnection conn = this.returnConnection(fileName))
{
conn.Open();
// retrieve the data using data adapter
OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [" + sheetName + "]", conn);
sheetAdapter.Fill(sheetData);
}
return sheetData;
}
It's worth to take a look at NPOI when it comes to read/write Excel 2003 XLS files. NPOI is a life saver.
I think you'll have to iterate your range and create DataRows to put in your DataTable.
This question on StackOverflow provides more resources:
Create Excel (.XLS and .XLSX) file from C#
This method does not work well when the same column in the excel spread sheet contains both text and numbers. For instance, if Range("A3")=Hello and Range("A7")=5 then it reads only Hello and the value for Range("A7") is DBNULL
private void Form1_Load(object sender, EventArgs e)
{
try
{
DataTable sheetTable = loadSingleSheet(#"C:\excelFile.xls", "Sheet1$");
dataGridView1.DataSource = sheetTable;
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message, "");
}
}
private OleDbConnection returnConnection(string fileName)
{
return new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileName + "; Jet OLEDB:Engine Type=5;Extended Properties=\"Excel 8.0;\"");
}
private DataTable loadSingleSheet(string fileName, string sheetName)
{
DataTable sheetData = new DataTable();
using (OleDbConnection conn = this.returnConnection(fileName))
{
conn.Open();
// retrieve the data using data adapter
OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [" + sheetName + "]", conn);
sheetAdapter.Fill(sheetData);
}
return sheetData;
I made method which can take alredy filtered data from Excel
Taking filtered data in Range format
Worksheet sheet = null;
sheet = (Worksheet)context.cDocumentExcel.Sheets[requiredSheetName];
DataTable dt = new DataTable();
sheet.Activate();
sheet.UsedRange.Select();
List<Range> ranges = new List<Range>();
Range usedrange = sheet.UsedRange;
foreach (var oneRange in usedrange.SpecialCells(XlCellType.xlCellTypeVisible))
{
ranges.Add(oneRange);
}
dt = (_makeTableFromRange(ranges));
Converting from Range to DataTable
private static DataTable _makeTableFromRange(List<Range> ranges)
{
var table = new DataTable();
foreach (var range in ranges)
{
while (table.Columns.Count < range.Column)
{
table.Columns.Add();
}
while (table.Rows.Count < range.Row)
{
table.Rows.Add();
}
table.Rows[range.Row - 1][range.Column - 1] = range.Value2;
}
//clean from empty rows
var filteredRows = table.Rows.Cast<DataRow>().
Where(row => !row.ItemArray.All(field => field is System.DBNull ||
string.Compare((field as string).Trim(), string.Empty) ==
0));
table = filteredRows.CopyToDataTable();
return table;
}