I am relatively new to C# and am developing an application that communicates with a local database (SQL Compact 3.5). I am fine with running standard select statements - but when it comes to getting that data into C# - I get a bit lost.
What I have so far is a 'delete' query that deletes all rows named 'Master'.
Now I have worked out that I actually need to get the IDs of those rows before I delete them (for database integrity purposes). I have no problems running a standard select query - my problem is getting a selection of rows from SQL CE into a C# application (using arrays or datatables or whatever is most logical/convenient).
This is what I have at the moment, but it only returns one value, not a selection:
string sql = "select listid from list where ShortDesc='Master'";
SqlCeCommand cmdGetOldMasterId = new SqlCeCommand(sql, DbConnection.ceConnection);
int oldKey = (int)cmdGetOldMasterId.ExecuteScalar();
Console.WriteLine("Old ID: " + oldKey);
I need to be able to do perform a foreach{ } loop on each of the returned rows. Any ideas how I can do this in C#?
You need to use a SqlCeDataReader instead of a ExecuteScalar if you suppose that your sql statement returns more thant one row of data
string sql = "select listid from list where ShortDesc='Master'";
SqlCeCommand cmdGetOldMasterId = new SqlCeCommand(sql, DbConnection.ceConnection);
SqlCeDataReader reader = cmdGetOldMasterId.ExecuteReader();
while(reader.Read())
{
Console.WriteLine(reader[0].ToString());
// or, if your listid is an integer
// int listID = reader.GetInt32(0);
}
another possibility is to use a SqlCeDataAdapter to fill a DataTable (this is less performant, but more useful if you need to process your data later in a different method)
string sql = "select listid from list where ShortDesc='Master'";
SqlCeCommand cmdGetOldMasterId = new SqlCeCommand(sql, DbConnection.ceConnection);
SqlCeDataAdapter da = new SqlCeDataAdapter(cmdGetOldMasterId);
DataTable dt = new DataTable();
da.Fill(dt);
....
foreach(DataRow r in dt.Rows)
{
Console.WriteLine(r["listid"].ToString());
}
SqlCeCommand has several execution methods
ExecuteNonQuery - to execute sql that does not need to return something
ExecuteScalar - for SELECT queries returning one value (don't mix with one row)
ExecuteReader - for SELECT queries returning >=0 rows
http://msdn.microsoft.com/en-us/library/182ax5k8.aspx
var reader = cmdGetOldMasterId.ExecuteReader();
while(reader.Read())
{
// reader[0], reader[1]...
}
Related
So I am creating a messaging application for a college project and I have a database of Users in Access, I have linked the database correctly and can execute statements but I am struggling with one problem, how to count the number of rows in a data table.
In fact, all I want to do is to count the total number of users and my teacher told me to get the data into a DataTable and count the number of rows. However, no matter how many users I have in the database, it always returns as 2.
int UserCount = 0;
using (OleDbConnection cuConn = new OleDbConnection())
{
cuConn.ConnectionString = #"DATASOURCE";
string statement = "SELECT COUNT(*) FROM Users";
OleDbDataAdapter da = new OleDbDataAdapter(statement, cuConn);
DataTable Results = new DataTable();
da.Fill(Results);
if (Results.Rows.Count > 0)
{
UserCount = int.Parse(Results.Rows[0][0].ToString());
}
}
The above code is a copy of what I was sent by my teacher who said it would work. Any help would be appreciated.
Also, sorry if this is a waste of time, still getting used to this StackOverflow thing...
Try replace Users with [Users]?
Because Users may be a key word of database.
Also the simpler way to get aggregate numbers is by ExecuteScalar method.
using (OleDbConnection cuConn = new OleDbConnection())
{
cuConn.ConnectionString = #"DATASOURCE";
string statement = "SELECT COUNT(*) FROM [Users]";
OleDbCommand cmd = new OleDbCommand (statement, cuConn);
cuConn.Open();
int count = (int)cmd.ExecuteScalar();
if (count > 0)
{
//
}
}
I successfully used your exact code (except the connection string) with sql server so maybe there is a problem with your #"DATASOURCE" or MS Access.
I have a SQL Server database which has a lot of information inside.
I want to select top 50 rows in a single query (which I did, with no problem) but then I want to update a column from false to true, so next time I select I wont select the same, my code looks like this:
string Command = "UPDATE HubCommands SET [Alreadytaken] = 'true' FROM (SELECT TOP 50 [CommandId],[DeviceId],[Commandtext], [HashCommand],[UserId] FROM HubCommands) I WHERE [HubId] = '18353fe9-82fd-4ac2-a078-51c199d9072b'";
using (SqlConnection myConnection = new SqlConnection(SqlConnection))
{
using (SqlDataAdapter myDataAdapter = new SqlDataAdapter(Command, myConnection))
{
DataTable dtResult = new DataTable();
myDataAdapter.Fill(dtResult);
foreach (DataRow row in dtResult.Rows)
{
Guid CommandId, DeviceId, UserId;
Guid.TryParse(row["CommandId"].ToString(), out CommandId);
Guid.TryParse(row["DeviceId"].ToString(), out DeviceId);
Guid.TryParse(row["UserId"].ToString(), out UserId);
Console.WriteLine("CommandId" + CommandId);
}
}
}
This code does work, and it updates what I ask it to update, but I don't get nothing in the data table, its like it is always updating but not selecting.
If I do a normal select it does work and give information.
Does anyone have any idea how to update and get some data back, in a single query?
So your question is:
How can I update a table in SQL Server using C# and return the truly updated
rows as a DataTable ?
First You have multiple issues in your query.
You should use 1 and 0, not true or false. SQL-Server has a bit datatype and not a Boolean.
Second, this is how you should've constructed your query:
DECLARE #IDs TABLE
(
[CommandId] uniqueidentifier
);
INSERT INTO #IDs
SELECT [CommandId] FROM HubCommands
WHERE [HubId] = '18353fe9-82fd-4ac2-a078-51c199d9072b' AND [Alreadytaken] = 0;
UPDATE HubCommands
SET [Alreadytaken] = 1
WHERE CommandId IN
(
SELECT [CommandId] FROM #IDs
);
SELECT * FROM HubCommands
WHERE CommandId IN
(
SELECT [CommandId] FROM #IDs
);
Wrap all the above in a single string and use SqlDataReader. No need for an Adapter in you case (Since we're mixing commands unlike what the adapter usually does):
var sqlCommand = new SqlCommand(Command, myConnection);
SqlDataReader dataReader = sqlCommand.ExecuteReader();
DataTable dtResult = new DataTable();
dtResult.Load(dataReader);
I highly advise you to create a stored procedure accepting HubId as a parameter that does all the above work. It is neater and better for maintenance.
I'm having some problems on my application since I'm not very experienced on the database handling, so far I've created my database with a table, and what I wanted to do is to show a specific data from the table as a variable.
My application has to do with chemical elements, therefore the table "elements" has all of them. I was thinking of making a random element generator using a random number to get any of the elements in the table with a query or something.
Random ra = new Random();
int random_anumber = ra.Next(1, 9);
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\Francisco\Documents\FormData.mdf;Integrated Security=True;Connect Timeout=30");
SqlDataAdapter adp = new SqlDataAdapter("SELECT * FROM elements", con);
I was thinking on putting the random_anumber instead of the "*" but it's still not showing a single element. Since I don't know how to show them of convert the data into a variable.
The "*" in the SQL statement is a field name selector and not a filter. So changing the * to something else won't limit your query to a single element. You have to add a where clause for that.
To solve this you can either use the SqlDataAdapter onto a DataSet and use the DataTable within the DataSet to grab a random row by using the random number as the index or run a simple query. I recommend running a query if all you need to do with this data is display a random element.
--- Update ---
MS SQL Server Statement:
SELECT TOP 1 * FROM table
ORDER BY NEWID()
MySQL Statement:
SELECT * FROM table
ORDER BY RAND()
LIMIT 1
The * is a wildcard character that select all columns/fields of the table. You can change the to a comma delimited list of columns/fields you want to retrieve from the database.
Hope that the Table elements having a unique Key Field(let it be element_id) then you can access the Random Element by Specifying the ID in the Where Clause, Then your Query will be like The following:
string querySQL="SELECT * FROM elements Where element_id=#id";
SqlCommand cmd = new SqlCommand(querySQL, con) // con is the Connection
cmd.Parameters.AddWithValue("#id", random_anumber);
// Get data using Adapter
This is how I do it everyday:
Note: Here you can see that I use Sqlite in my example. You can use SQL by removing the Lites and using the right classes in SQL respectively.
string ConnectionString = "data source={0}; initial catalog={1}; integrated security=true; application name= <Your App Name>" providerName="System.Data.SqlClient";
string DatabasePath = "<Your Path to your database>";
string commandstring = "SELECT * FROM elements";
using (SQLiteCommand MyCommand = new SQLiteCommand(commandstring, Connection))
{
using (SQLiteDataReader MyReader = MyCommand.ExecuteReader())
{
while (MyReader.Read())
{
// Here is your result:
// You can do anything that you want with it.
// The 0 shows the first column. If your result returns more than one column, //you can use other numbers like 1,2..n to get other columns out of your data //reader.
MyReader.GetString(0);
}
}
}`
I'm trying to display the number of records in the data reader. Here's what I tried.
if (mybtnreader1.HasRows)
{
using (DataTable dt = new DataTable())
{
dt.Load(mybtnreader1);
int rc = dt.Rows.Count;
MessageBox.Show("Have "+rc+"records");
}
}
Though it has records it is always displaying 0. How should it be corrected or is there any other way to get the number of records in a data reader?
I'm using this code to display the data.
while(mybtnreader1.Read())
{
MessageBox.Show(mybtnreader1.GetValue(0) + " "+mybtnreader1.GetValue(1)+" ");
}
It is showing the data but when it comes to the number of records it is displaying 0.
After looping through the results of your query you can use RecordsAffected:
mybtnreader1 = command.ExecuteReader();
while(mybtnreader1.Read())
{
///do your stuff
}
mybtnreader1 .Close();
MessageBox.Show(mybtnreader1 .RecordsAffected.ToString());
A DataReader is forward-only read-only so you can't get the number of records before looping through them all. While you loop through you can count, but not before.
If you need to know the number of records ahead of time and want the performance and memory advantages of a DataReader, then change your query to run two queries.. first the same underlying query with a select count(*)... and then the actual query. Depending on the query, this will obviously affect performance. It won't be double the time due to caching, but is additional processing time. You'll have to weigh the need for having the count ahead of time vs the advantages of using a DataReader vs a DataTable.
For example, if you're querying every record from a table like this:
string sql = "SELECT * FROM MyTable";
using(var dataReader = ...)
Then you can do this instead:
string sql = #"
SELECT COUNT(*) FROM MyTable;
SELECT * FROM MyTable;
};
using(var dataReader = ...)
{
... process first result in data reader (count) ...
if (dataReader.NextResult)
{
... process the second result (records) ...
}
}
You cannot do it directly with Datareader. you can do it like below -
SqlDataReader reader = command.ExecuteReader();
DataTable dt_results = new DataTable();
dt_results.Load(reader);
int count= dt_results.Rows.Count;
if(count>0)
{
//Hey! we Have records for this query
}
else{
//Sorry! No Records Exist for this query
}
Process
I am writing a C# application which will need to retrieve 4 million records(ID) from a SQL table in database A.
I then need to use each ID to select a row of record each from another SQL table in database B.
Once I have this row I then need to update another SQL table in database C
Questions
What’s the most efficient way to retrieve and store the data in Step 1?
a. Should I load this in a list string?
b. Do you recommend doing batches initially?
What the most efficient way to achieve steps 2 and 3
To retrieve the 4M records you're going to want to use a SqlDataReader - it only loads one row of data into memory at a time.
var cn = new SqlConnection("some connection string");
var cmd = new SqlCommand("SELECT ID FROM SomeTable", cn);
var reader = cmd.ExecuteReader();
while (reader.Read())
{
var id = reader.GetInt32(0);
// an so on
}
reader.Close();
reader.Dispose();
cn.Close();
Now, to handle two and three, I would leverage a DataTable for the row you need to retrieve and then a SqlCommand on the third database. This means that inside the reader.Read() you can get the one row you need by filling a DataTable with a SqlDataAdapter and the issuing an ExecNonQuery against a SqlCommand for the UPDATE statement.
Another way of writing the above, and it's a bit safer, is to use the using statement:
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetInt32(0);
// an so on
}
}
that will eliminate the need for:
reader.Close();
reader.Dispose();
and so you could also issue that for the SqlConnection if you wanted.
SQLBulkCopy class might help.
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx