I am writing a C# WPF application with controls bound to a MySQL 5.5 database. I'm populating a DataTable using a MySqlDataAdapter, passing in a MySQL SELECT query.
When the query is something trivial, like SELECT * FROM People or SELECT LastName, FirstName, PersonID FROM People, all is well and my ListBox control ends up populated with the expected names.
When the query contains a fairly simple CONCAT operator, though, the query silently fails and the ListBox stays empty. In particular neither of the following have worked, even though both work fine from within the MySQL command line.
SELECT CONCAT(LastName, FirstName) as Name FROM People
SELECT CAST(CONCAT(LastName, FirstName) AS CHAR) as Name FROM People
Both LastName and FirstName are defined as VARCHAR. So, I wouldn't expect this to be an instance of CONCAT returning a binary string in any case. I mention that because it appears to have been the problem for similar issues that other folks have mentioned.
I'd imagine the DataAdapter attempts to parse your query into an internal format so that it can do things like generate Update and Insert commands.
Can you fill your datatable using a MySqlDataReader instead? This is probably only helpful if you are not planning to do database updates with the DataTable
Going from memory...
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader reader = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(reader);
Related
For example, I have a script that contains
insert into #temp from TABLES
insert into #temp1 from #temp
select * from #temp
I already have a C# MVC application. I just want to be able to execute the script above to display the #temp table on my front-end. I have seen the function ExecuteNonQuery(), however, it only shows the rows affected. Is there anyone that can point me a guide to solve this issue?
EDIT: I just want to run the script above and obtain the results, i don't want to rewrite the script in a framework.
Here is a sample for ExecuteNonQuery:
private void ExecuteNonQuery(string queryString, string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
}
From MSDN
And you can call your inserts like this: ExecuteNonQuery("insert into #temp from TABLES", connectionString);
For reading you can use ExecuteReader (MSDN) But if your table has many columns, this can be tedious to display all the columns. I prefer to use micro ORM (or data mapper otherwise) like Dapper - it is easy to use, minimum set up and with plenty of documentation.
Some people advise to use Entity Framework, but for this case it looks like will be an overkill. Also it has a steep learning curve.
If you want to read data from temporary table so use the ExecuteReader() and refer the following code.
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var myString = rdr.GetString(0); //The 0 stands for "the 0'th column", so the
first column of the result.
// Do somthing with this rows string, for example to put them in to a list
listDeclaredElsewhere.Add(myString);
}
}
For select you have can use DataSet object and using DataAdapter fill data to DataSet
DataSet ds=new DataSet();
SqlDataAdapter da=new SqlDataAdapter(commandObject);
da.fill(ds);
DataSet ds=new DataSet();
SqlDataAdapter da=new SqlDataAdapter(commandObject);
da.fill(ds);
yes, that would work as well. but be aware that you are working with a DataSet (not DataTable on purpose?), and both DataSet and it's matching DataTable(s) are all dynamic objects without type safety (i.e. you are working with ds.Tables[0].Rows[0][2] as string; ).
good luck with the runtime exceptions.
My SQL query is not working. The query is something like this:
QueryString = SELECT material FROM tbl1 WHERE vendor = UserInputVar;
This query would run after the UserInputVar was made by the user from selecting a value in a combobox(say, combobox1). What this query does is that the results fetched by this query will populate another combobox(say, combobox2).
I tried to find the solution online but nothing works on my current problem. I tried to do it on my own by trying the following:
Use MySqlDataAdapter together with MySqlCommandBuilder, then use the adapter to fill a data table and that data table would be the datasource
Put QueryString and connect_DBstring in a MySqlCommand constructor and use a variable instance of MySqlCommand. Then, use adapter and commandbuilder to fill the datasource of second combobox.
Any suggestions and links would help. I really don't know what to do since I usually use MySqlDataReader for SELECT statements and MySqlDataAdapter for INSERT statements. I haven't had an experience using SELECT with MySqlDataAdapter before
Don't use user input in SQL statement since it creates possibility to make SQL injections.
using (MySqlConnection connection = new MySqlConnection(con))
{
try
{
connection.Open();
using (MySqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT material FROM tbl1 WHERE vendor=#vendor"
command.Parameters.AddWithValue("#vendor", UserInputVar);
command.ExecuteNonQuery();
connection.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
As for populating combobox from SQL query take a look at the following post:
https://stackoverflow.com/a/12495086/1099716
I managed to solved the problem. It turns out my way of parameterized query is wrong but I finally corrected it. Instead of using MySqlCommand parameters, I used MySqlDataAdapter parameters instead. I never knew about it at first but thankfully I know now.
When I query a SQLite Table from C# using an asterisks like:
string SQLText = "SELECT * FROM [TableName]";
SqliteCommand Command = new SqliteCommand (SQLText, Database);
(?) Result = (?)Command.ExecuteScalar ();
Since there is obviously going to be more than one data value (And Typically of different types) is it returned as an array of Objects "object[]".
What Data Type is being returned? If you find out please post where you got your info so I can avoid asking stupid questions again.
Sean
ExecuteScalar will return only a single value, the first row/first column of the result set. It is typically used to retrieve a single value (for example, an aggregate value) from a database, like COUNT etc.
You need a collection of records back. Use:
SQLiteDataReader
SQLiteDataAdapter to fill a DataTable or DataSet
See: Retrieving data with SqliteDataReader
you should use
command.ExecuteReader();
if you want to get more than one rows. ExecuteScalar() will return only single value;
ExecuteScalar() is only used for queries which are expected to return only single values like
"SELECT COUNT(*) FROM [TableName]"
You can read about ExecuteScalar() and ExecuteReader()
This is bugging me. Something so simple and it does not work. What could I be doing wrong?
Here is the code I am using ...
string strSQL = "SELECT ac.ContactEmail AS fldEmail FROM vwApprenticeshipContactDetails ac WHERE (ac.ApprenticeshipID = #ApprenticeshipID)";
SqlCommand cmd2 = new SqlCommand(strSQL, cnn);
cmd2.Parameters.Add("#ApprenticeshipID", SqlDbType.Int).Value = wsAppID;
Object fldEmail = cmd2.ExecuteScalar();
Believe it or not, the above returns what looks like an array when I debug and look at the value of 'fldEmail'. In otherwords it's empty, nothing or null (cannot tell as the output window shows an array). I have run this directly in SQL server and I get the email showing fine. Could the '#' character inside the database field be causing something here?
The email I expected back is 'g.somebody#domain.com.au', which to me looks ok.
UPDATE
I replaced the ContactEmail field above, with another column name from the database and it comes back fine. Not sure why emails are an issue. The datatype by the way here is VARCHAR(50).
UPDATE
In debug mode I noticed it returns system.DBNull data type (and digging deeper it returns empty), but why? I ran the exact same query with the correct parameter in SQL server and I get a email showing. Strange
Thanks
Solved it!
For some reason (and I am a noob when it comes to email objects in C#), but an ExecuteScalar is not properly populating as it was not "read" first. What I mean by this is that when I changed ExecuteScalar to an SqlReader, it worked because I am "forcing" the read of the SQL before testing it.
So my code looks now like this and it returns an email!
strSQL = #"SELECT TOP 1 ContactEmail FROM vwApprenticeshipContactDetails WHERE ApprenticeshipID = #ApprenticeshipID";
SqlCommand cmd2 = new SqlCommand(strSQL, cnn);
cmd2.Parameters.Add("#ApprenticeshipID", SqlDbType.Int).Value = wsAppID;
using (SqlDataReader rdr = cmd2.ExecuteReader())
{
string fldEmail = "support#domain.com.au"; //this is as a default in case the sql above does not return a value
while (rdr.Read())
{
fldEmail = rdr.GetSqlValue(0).ToString();
}
}
I was avoiding SqlReader initially because I thought they were specifically designed for when reading in more than one row of data. In my case I know the parameter given only returns one row or nothing at all.
Thanks
At the first change select to top 1 for performance reason.
string strSQL = "SELECT Top 1 ac.ContactEmail AS fldEmail FROM ...
If you dont have any result in query, you will get null value as result.
You can check how many records returned by query in sql server profiler.
Also you can check your connection string to make sure are you connected to correct database.
I am converting data from a CSV file into a database. I put the data from the CSV file into a DataTable and am trying to validate the data.
One thing I want to check is that all of the values in a certain column of the DataTable (let's call it PersonID) are found in the columns of a table in the database I'm converting to (let's call that PeopleID).
So, I want to check if all of the values of PersonID are listed in the PeopleId table.
I have the results of the DataTable as follows:
var listOfPersonIdsInData = arguments.DataTable.Select("PersonId");
And I query the database to get the values of the PeopleId column:
var listOfPeopleIdsInDatabase = checkQuery.Execute<DataColumn>(#"SELECT DISTINCT PeopleId FROM People");`
What would be the best way to go about checking this in C#? I realize it's a somewhat basic question but the way I'm thinking of doing it is using two arrays. Read in the results of each into an array, then cycle through each value of array 1 to check if it's in array 2.
I feel like I'm re-inventing the wheel. I would really like to know a better way if there is one. If anyone could provide any advice I'd greatly appreciate it.
If you're using SQL 2008 I would recommend that you just pass the DataTable as parameter as a Table-Valued Parameter to a stored procedure or a Parameterized query and then use an Anti Join or Not In or Not Exists to determine if there are any rows in the DataTable that aren't in the SQL Table.
e.g.
Create the type
CREATE TYPE dbo.PersonTable AS TABLE
( PersonId int )
Then the proc
CREATE PROCEDURE usp_ValidateDataTable
(#CheckTable dbo.PersonTable READONLY) as
BEGIN
SELECT c.PersonID
FROM
#CheckTable c
WHERE
c.Person NOT IN (SELECT PersonID from dbo.People)
END
C# Code
SP Call
SqlCommand cmd= new SqlCommand("usp_ValidateDataTable" , cnn);
SqlParameter tvpParam = cmd.Parameters.AddWithValue("#CheckTable", listOfPersonIdsInData );
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.PersonTable";
SqlDataReader rdr = cmd.ExcuteReader();
C# Code
Parameterized Query Call
string query = #" SELECT c.PersonID
FROM #CheckTable c
WHERE c.Person NOT IN (SELECT PersonID from dbo.People)";
SqlCommand cmd= new SqlCommand(query , cnn);
SqlParameter tvpParam = cmd.Parameters.AddWithValue("#CheckTable", listOfPersonIdsInData );
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.PersonTable";
SqlDataReader rdr = cmd.ExcuteReader();
I have had to migrate much information and so far I think the best is:
Create a flat table with the information from the CSV and load all the data there
Create in the same SQL methods to extract standardized information
Construct a method in the same SQL crossing normalized information with the raw data
is really fast especially when the number of records is quite large (greater than 1M), plus you avoid the problem of optimizing your RAM management script/program. also load CSV to MySQL data is really easy check this
a tip: parameterized method for import and verify with an offset and limit value