How to select number from Excel file? - c#

I use this code to load an Excel file into a datatable:
public static DataTable ImportExcelFile(string connectionString)
{
DbProviderFactory factory =
DbProviderFactories.GetFactory("System.Data.OleDb");
var listCustomers = new DataTable();
using (DbConnection connection = factory.CreateConnection())
{
if (connection != null)
{
connection.ConnectionString = connectionString;
using (DbCommand command = connection.CreateCommand())
{
// Cities$ comes from the name of the worksheet
command.CommandText = "SELECT * FROM [Sheet1_2$]";
connection.Open();
using (DbDataReader dr = command.ExecuteReader())
{
listCustomers.Load(dr);
}
}
}
}
return listCustomers;
}
The problem is, some columns in the Excel file, for example, AccountID, contains both string data ('quanmv') and number (123456). When I use this code, it just ignores cell with number value, and leave it with blank.
How can I fix that?
Thank you so much.

By default, the connection to excel tries to guess data types of columns. If it guesses wrong, it may leave nulls where types don't convert. You can add IMEX=1 to the connection string to turn off this automatic guessing, and treat all values as strings.

Related

Convert column with mixed data to string

I have an excel file with 1 column, the column contains mixed data,int & string.
After I read the data from the excel file, I saw that the cell with data AZ-965 is null.
this is my string connection
return new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
+ excel + ";Extended Properties='Excel 12.0;HDR=YES;IMEX=1;ImportMixedTypes=Text;TypeGuessRows=0;';");
and this how I read data from Excel file
private static List<T> GetImportedData<T>(string sheet, OleDbConnection myConnection,
List<string> column, ImportDataView<T> view) where T : IImportableData
{
var cols = string.Join( ",", column.Select(Cast));
var formattableString = $"select {cols} from [{sheet}$]";
using (var MyCommand = new
OleDbDataAdapter(formattableString, myConnection))
{
using (var DtSet = new DataSet())
{
int nbRow = 0;
MyCommand.Fill(DtSet);
var dt = DtSet.Tables[0];
var rows = dt.AsEnumerable();
var convertedList = rows
//.AsParallel()
.Select(x => GenerateImport<T>(x, column, ref nbRow, view))
.ToList();
return convertedList;
}
}
}
private static string Cast(string arg)
{
return $"IIf(IsNull([{arg}]), '', CStr([{arg}]))";
// return $"CStr([{arg}]) as {cleanName(arg)}";
//return $"[{arg}]";
}
I check this link, but nothing is work, same isue
TypeGuessRows in your connection string is not a connection string property, at least not that I'm aware. It's a registry key:
https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/initializing-the-microsoft-excel-driver?tabs=office-2016
So I don't think it's doing what you think it is... or anything for that matter.
If you can't control the registry or the content of the file, my only suggestion would be to change the header property in the connection string (HDR=YES) to "no" so that it reads the first record in as text... then you can effectively trash the first row.
It's not a great solution, but it should do what you seek.
Alternatively, you can try reading the content using a DbDataReader instead of using a data adapter:
using (OleDbCommand cmd = new OleDbCommand(formattableString, conn))
{
using (OleDbDataReader reader = cmd.ExecuteReader())
{
string column = reader.IsDBNull(0) ? null : reader.GetValue(0).ToString();
}
}
Based on my inferences on what you are trying to do, the data reader may actually offer some other advantages as well.

Need advice on how to get data from a database into a list of objects, without knowing beforehand what database I will be connecting to

I'm trying to write a function in an MVC C# controller into which I can pass in the table name, server name, database name, username and password. This function is being called from an Ajax call, so it needs to return JSON. I'm using to using entity framework, so I'm sort of new to this - I've been trying to use SqlDataReader, and then automatically put all data return into a list of objects, which I can then return to the Ajax, but I'm not even getting close - all of the methods using SqlDataReader seem to require knowing what rows you want to select in advance, so I have no real clue what do to or try next. Has anybody got any advice on how to achieve this?
Basically, it's for a project I've been tasked with where someone can fill in a form with the connection string, and sql query, and the scripts will go to the controller and return the data. The user can then pick what column(s) they want to use, using dc.js, I will create whatever chart they chose based on whatever columns they chose, based on the returned data. It's melting me head...
This is something I have in a project:
/// <summary>
/// Get all of the SQL data from "tableName" using "connectionString"
/// </summary>
public static DataTable GetSqlDataAsDataTable(string tableName, string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand(string.Format("SELECT * FROM [{0}]", tableName), connection))
{
cmd.CommandType = CommandType.Text;
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
using (DataTable dt = new DataTable())
{
try
{
sda.Fill(dt);
}
catch (Exception)
{
// handle it
}
return dt;
}
}
}
}
}
Once you have that, you can convert the DT to JSON as described in this other answer: https://stackoverflow.com/a/17398078/4842817
public static string GetJSON(string connectionString, string tableName)
{
try
{
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
SqlCommand command = new SqlCommand($"SELECT * FROM {tableName}", connection);
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataTable dataTable = new DataTable();
adapter.Fill(dataTable);
connection.Close();
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dataTable.Rows);
return json;
}
catch { return string.Empty; }
}
The code above requires references to System.Data and System.Data.SqlClient as well as the open-source Nuget package called Newtonsoft.Json.
It will open up a connection based on the connection string provided, select all columns from the specified table and populate a DataTable object with this information.
Newtonsoft.Json's JsonConvert.SerializeObject(object) method will serialize the DataRowCollection (dataTable.Rows) to a JSON string to be returned.
I would use Dapper and Newtonsoft.Json from nuget and do it like this:
public string GetTableContentsAsJson(string serverName, string databaseName, string userName, string password, string tableName)
{
System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
builder["Data Source"] = serverName;
builder["integrated Security"] = false;
builder["Initial Catalog"] = databaseName;
builder["User ID"] = userName;
builder["Password"] = password;
Console.WriteLine(builder.ConnectionString);
using (var connection = new SqlConnection(builder.ConnectionString))
{
connection.Open();
var images = connection.Query($"SELECT * FROM {tableName}");
string s = JsonConvert.SerializeObject(images);
return s;
}
}
Hi Entity framework itself providing the freedom to choose databases dynamically. Write a procedure for fetching the column details and return the result, it will solve your issue.

How to use C# connect to mysql and get json data?

As mentioned above:
I'm using C# to connect to a MySQL database and I want to read JSON data type.
I use the method MySqlCommand.ExecuteReader:
using (MySqlConnection sconn = new MySqlConnection(sqlConnectString))
{
sconn.Open();
String sql_Command = #"SELECT `id` FROM orders.jsontest;";
using (MySqlCommand scmd = new MySqlCommand(sql_Command, sconn))
{
**MySqlDataReader sdr = scmd.ExecuteReader();** // fatal error
DataTable datatable = new DataTable();
// ...
}
}
Can it be that I cannot use ExecuteReader here?
I know this question is old, but just in case you do not yet have a solution to your problem or anyone else encounters a similar problem, the following code should work for you:
private IEnumerable<int> GetIds()
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
string commandText = #"SELECT id FROM jsontest"; // Assuming that `orders` is your database, then you do not need to specify it here.
using (MySqlCommand command = new MySqlCommand(commandText, connection))
{
MySqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
yield return reader.GetInt32(0);
}
}
}
}
Now what you should pay attention to is this line
while (reader.Read())
which fetches results from the jsontest table as long as the MySqlDataReader can still read valid results and this line
yield return reader.GetInt32(0);
which instructs the reader to get and return each record of the fetched table one at a time as an Int32 (int). You need to change this if your tables column type is not INT.
Since you selected just one column (i.e. "SELECT id"), the parameter is 0, because your fetched resul table consists of one column only.
Additionally, in your code you seem to want to get the results as a DataTable; if so, you should use MySqlDataAdapter instead of the MySqlDataReader as follows:
DataTable resultTable = new DataTable("ResultTable");
MySqlDataAdapter adapter = new MySqlDataAdapter(command);
adapter.Fill(table);
Correct your sql command
String sql_Command = #"SELECT id FROM orders.jsontest";

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.

How do I get an DataTable from IDataReader?

I'm trying to get a DataTable or DataSet from an IDataReader, but I'm failing. Here's the code:
string sql = #"SELECT ID, DOCNUMBER FROM TBDOCUMENT";
using (IDbConnection conn = CreateConnection(provider, connectionString))
{
conn.Open();
using (IDbCommand command = conn.CreateCommand())
{
command.CommandText = sql;
IDataReader reader = command.ExecuteReader();
using (reader)
{
while (reader.Read())
{
long key = reader.GetInt64(0);
decimal value = reader.GetDecimal(1);
}
}
}
}
I'm using IDbConnection and IDbCommand because it will works with three different databases (the method CreateConnection(provider, connectionString) gets the specific type of connection according to the database).
My query gets an ID (as Int64) and a DocNumber (as Decimal), but every time I try to get the decimal value, it throws an OverflowException with a message: "Conversion overflows." Both of values are important to me, but I don't know how do I get these values.
Actually, the code I'm not trying to convert to a DataTable, I have to get the value of the two without exception.
Some help?
Though I haven't check by executing but it should work...
// Load the data into the existing DataSet.
DataTableReader reader = GetReader();
dataSet.Load(reader, LoadOption.OverwriteChanges,
customerTable, productTable);
// Load the data into the DataTable.
SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
DataTable dt = new DataTable();
dt.Load(dr);

Categories