How to set database table values in a string? - c#

I have a SQL Server database table EmpDetails and it contains two row values. I want to save these values into another table. but as per my code I can get only first row value. How to get all rows values from my EmpDetails table.
My sample code is:
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString);
SqlCommand cmd = new SqlCommand ("select e.MachID,e.Name,e.EmpCode,T.TypeName from EmpDetails e,EmpType t where e.EtypeID=t.EtypeID and e.Deptid='" + dddep.SelectedItem.Value + "'",conn);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
sda.Fill(ds);
string name = Convert.ToString(ds.Tables[0].Rows[0]["Name"]);
string code = Convert.ToString(ds.Tables[0].Rows[0]["EmpCode"]);
string type = Convert.ToString(ds.Tables[0].Rows[0]["TypeName"]);

You could try to use a loop because currently you are getting values from the first row when you say index [0].
Example:
//let n be the total rows
for(int i = 0; i < n; i++)
{
string name = Convert.ToString(ds.Tables[0].Rows[i]["Name"]);
string code = Convert.ToString(ds.Tables[0].Rows[i]["EmpCode"]);
string type = Convert.ToString(ds.Tables[0].Rows[i]["TypeName"]);
}
Hope it helps

What you can do is iterate the Rows in each Table using foreach. Since Tables[0].Rows return a DataRowCollection, you can directly put the rows in a loop:
var rows = ds.Tables[0].Rows;
foreach (DataRow row in rows)
{
var name = row["Name"];
var code= row["EmpCode"];
var type= row["TypeName"];
}
And you can use a collection to store the values for each column for each row, maybe like a list that uses a simple data model.
Hope that works!

if (ds !=null && ds.Tables.count > 0 ) {
foreach (row in ds.Tables["EmpDetails"].Rows)
{
var name = row["Name"];
var EmpCode= row["EmpCode"];
var TypeName= row["TypeName"];
}
}

Related

Getting specific column data from database in C#

I have created a search function that returns product data in a DataGridView (data is coming from local database), it does work but I need to have control over returned data in my grid view.
Current behavior
It returns all columns of database row in DataGridView
What I want
Returning only 2 or 3 columns of searched item instead of all columns
Create new list of searched items so I can edit those returned data
Logic
Search for product
Get product name and price from database, add custom quantity field make new list and add this item to show in DataGridView
Be able to change quantity field in DataGridView
Code
Here is my search code that returns all columns of product table
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["SampleDatabaseWalkthrough.Properties.Settings.SampleDatabaseConnectionString"].ConnectionString))
{
if (cn.State == ConnectionState.Closed)
cn.Open();
using (DataTable dt = new DataTable("Products"))
{
using (SqlCommand cmd = new SqlCommand("select * from Products where Id=#Id or Name like #Name", cn))
{
cmd.Parameters.AddWithValue("Id", searchBox.Text);
cmd.Parameters.AddWithValue("Name", string.Format("%{0}%", searchBox.Text));
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);
// Following line will show all columns of founded product and replace it with next search result
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
selectedItems.DataSource = dt;
}
}
}
PS: Code above finds products based on id or name entered in search field and return all columns of product row.
Idea:
I think I can be able to create my list after finding product but the issue I'm facing is that I'm not sure how to get those specific columns from my dt (table row),
Here is what I've tried and failed (commented)
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["SampleDatabaseWalkthrough.Properties.Settings.SampleDatabaseConnectionString"].ConnectionString))
{
if (cn.State == ConnectionState.Closed)
cn.Open();
using (DataTable dt = new DataTable("Products"))
{
using (SqlCommand cmd = new SqlCommand("select * from Products where Id=#Id or Name like #Name", cn))
{
cmd.Parameters.AddWithValue("Id", searchBox.Text);
cmd.Parameters.AddWithValue("Name", string.Format("%{0}%", searchBox.Text));
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);
//selectedItems.DataSource = dt; //<-- changed with lines below
List<string> items = new List<string>();
items.Add(dt); // <-- here is the issue (it expect to get string of my table row let say: Price column, but I don't know how to get Price column value from dt)
selectedItems.DataSource = items;
}
}
}
PS: code above is just idea and obviously I am not sure if it is best way to do it or not that's why I'm asking here :)
Any suggestions?
Update
I've created new class and added my data to that class as following
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Price { get; set; }
public string Qty { get; set; }
}
Then in my query I added
List<Item> itemList = new List<Item>();
for (int i = 0; i < dt.Rows.Count; i++)
{
Item item = new Item();
item.Id = Convert.ToInt32(dt.Rows[i]["Id"]);
item.Name = dt.Rows[i]["Name"].ToString();
item.Price = dt.Rows[i]["SellPrice"].ToString();
item.Qty = dt.Rows[i]["Qty"].ToString();
itemList.Add(item);
}
selectedItems.DataSource = itemList;
Now it does return data in my selectedItems but when I search for next product instead of adding it to the list it replace it with first product.
According to your sql query you are selecting all columns of the table.
To get the specific columns please change your sql query as such:
SqlCommand cmd = new SqlCommand("select Products.id, Products.name from Products where Id=#Id or Name like #Name", cn);
Thank you.
As per my understanding based on the comments, you are looking for some Linq code.
You only need to convert your result to a list that you could use.
Here is some code that might help you achieve this.
var result = dt.AsEnumerable().Select(x=> new {
Id = x["Id"],
Name = x["Name"],
Quantity = {Your Logic here}
});
selectedItems.DataSource = result;
You can then assign result to your datasource. You did not specify what your datasource is assigned to (selectedItems) so I do not know what type it is. but this should theoretically work. Just remove Quantity = {Your Logic here} from the code and see if it display's after which you could then just add it back and populate what you want Quantity to be
UPDATE
Because selectedItems is a DataGridView it requires a DataTable object to display the data. In which case you can not use an anonymous list as I created you would need something like this.
DataTable dtResult = new DataTable();
dtResult.Columns.Add("Id");
dtResult.Columns.Add("Name");
dtResult.Columns.Add("Quantity");
var result = dt.AsEnumerable().Select(x=> dtResult.Rows.Add(x["Id"],
x["Name"],
{Your Logic for Quantity here}
));
selectedItems.DataSource = result;
If you want to test this solution you can create a console application in c# and do something like where you can see the datasource is correct.
You could refer to the following code to show specific column data from database in winform datagirdview.
private void button1_Click(object sender, EventArgs e)
{
string str = "str";
SqlConnection connection = new SqlConnection(str);
connection.Open();
string sql = "select * from Product where Id=#Id or Name like #Name";
SqlCommand command = new SqlCommand(sql,connection);
command.Parameters.AddWithValue("#Id", textBox1.Text);
command.Parameters.AddWithValue("#Name", string.Format("%{0}%", textBox1.Text));
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataTable table = new DataTable();
adapter.Fill(table);
var dt = from t in table.AsEnumerable()
select new
{
//Name=t.Field<string>("Name"), //The same way to show other columns data
Price = t.Field<string>("Price")
};
dataGridView1.DataSource = dt.ToList();
}
Result:
Database:

How would I show if a column in a DataGridView has data with just an X

I have a DataGridView with 4 columns. The code I'm using to build its datasource is this:
DataTable vTbl = new DataTable();
using(SqlConnection c = new SqlConnection(ConStr))
{
string query = "select site, username, password, notes from Passwords order by site, username";
using(SqlDataAdapter da = new SqlDataAdapter(query, c))
{
c.Open();
vTbl.Clear();
da.Fill(vTbl);
c.Close();
}
}
dataGridView1.DataSource = vTbl;
Now the fourth column which contains notes is a data type of nvarchar(max) in the table. So what I'd like to do is just show a mark (like an X) if this field is not empty or nulled and show nothing if the field IS empty or nulled.
I'm thinking there is something to do with the query variable, but I just can't place it.
Can someone please help me out?
Thanks,
Bob Gatto
Here is simple way using linq :
vTbl.Columns.Add("X", typeof(string));
foreach(DataRow row in vTbl.AsEnumerable())
{
if (row.Field<string>(3).Length > 0)
{
row[4] = "X";
}
}
vTbl.Columns.Remove("Column Name");

Iterate Multiple DataTables

I have a SQL Server stored procedure that I run two select statements. I can easily return one select statement and store it in a DataTable but how do I use two?
How can I set my variable countfromfirstselectstatement equal to the count returned from my first select statement and how can I set my variable countfromsecondselectstatement equal to the count returned from the second select.
private void ReturnTwoSelectStatements()
{
DataSet dt112 = new DataSet();
using (var con = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand("Return2SelectStatements", con))
{
using (var da = new SqlDataAdapter(cmd))
{
cmd.CommandType = CommandType.StoredProcedure;
da.Fill(dt112);
}
}
}
DataTable table1 = dt112.Tables[0];
DataTable table2 = dt112.Tables[1];
string countfromFirstSelectStatement = table1.Rows.Count().ToString();
string countfromSecondSelectStatement = table2.Rows.Count().ToString();
//I only want to iterate the data from the 1st select statement
foreach (DataRow row in dt112.Rows)
{
}
}
You could also directly use the DbDataReader (cmd.ExecuteReader()), which gives you NextResult to advance to the next result set. DataTable.Load allows you to load rows from the data reader to the table.
DbDataAdapter is really a bit of an overkill for just reading data into a data table. It's designed to allow the whole CRUD-breadth of operation for controls that are abstracted away from the real source of data, which isn't really your case.
Sample:
using (var reader = cmd.ExecuteReader())
{
dataTable1.Load(reader);
if (!reader.NextResult()) throw SomethingWhenTheresNoSecondResultSet();
dataTable2.Load(reader);
}
Fill a Dataset with both select statements and access it:
....
DataSet dataSet = new DataSet();
da.Fill(dataSet);
....
DataTable table1 = dataSet.Tables[0];
DataTable table2 = dataSet.Tables[1];
string countfromFirstSelectStatement = table1.Rows.Count.ToString();
string countfromSecondSelectStatement = table2.Rows.Count.ToString();

C# sql IF NOT EXIST statement not working?

Not sure if this is written correctly but it looks correct. I am wanting to update a record if the id already exists and insert if not.
DataSet ds = new DataSet();
ds.ReadXml(XDocument.Load(Application.StartupPath + #"\xml1.xml").CreateReader());
using (var conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + Application.StartupPath + "\\Database3.mdb"))
{
conn.Open();
// make two commands here
var commInsert = new OleDbCommand("Insert INTO Table1 (description, active) VALUES (#iq_question,#active);", conn);
var commUpdate = new OleDbCommand("UPDATE Table1 SET description=#iq_question,active=#active WHERE ID=#question_id;", conn);
// here add your parameters with no value
//string question_id = row[0].ToString();
//string iq_question = row[1].ToString();
//string active = row[4].ToString();
commInsert.Parameters.Add(new OleDbParameter("#iq_question", OleDbType.VarChar));
commInsert.Parameters.Add(new OleDbParameter("#active", OleDbType.VarChar));
commUpdate.Parameters.Add(new OleDbParameter("#question_id", OleDbType.AutoNumber));
commUpdate.Parameters.Add(new OleDbParameter("#iq_question", OleDbType.Text));
commUpdate.Parameters.Add(new OleDbParameter("#active", OleDbType.Text));
foreach (DataTable table in ds.Tables)
{
foreach (DataRow row in table.Rows)
{
// here only reset the values
commUpdate.Parameters["#question_id"].Value = row[0].ToString();
commUpdate.Parameters["#iq_question"].Value = row[1].ToString();
commUpdate.Parameters["#active"].Value = row[4].ToString();
int recs = commUpdate.ExecuteNonQuery();
if (recs < 1) // when no records updated do insert
{
commInsert.Parameters["#iq_question"].Value = row[1].ToString();
commInsert.Parameters["#active"].Value = row[4].ToString();
commInsert.ExecuteNonQuery();
}
}
}
commInsert.Dispose();
commUpdate.Dispose();
conn.Close();
}
System.Windows.Forms.MessageBox.Show("Updated Latest Data Was Succesfull");
I either get an error on the insert saying it will create duplicate content, or it creates more rows with different data. So say I should be getting 10 rows from the xml file, the first time I run it I get the 10 rows with the correct data. If I run it again, I end up with 10 more so being 20 but the last 10 rows show different data. I don't think I am identifying the rows in the xml file correctly and I need to do some research on that part.
There is no Exists for MS Access. The engine is much more primitive than Sql Server. See here: Microsoft Access SQL. I think, what you can do is:
myCommand.CommandText = "UPDATE Table1 SET description=#iq_question,active=#active WHERE ID=#currentRow";
......
int recs = myCommand.ExecuteNonQuery();
if (recs < 1) // when no records updated do insert
{
myCommand.Parameters.Clear();
myCommand.CommandText = "Insert INTO Table1 VALUES(#iq_question,#active)";
.....
}
This is still 2 statements but you can save some coding by not doing Select first. Because ExecuteNonQuery will tell you if you updated anything
Another thing is that your code is a bit inefficient. You have nested loop where you can reuse same command and connection. Yuu can do this
using (var conn = new OleDbConnection(.......))
{
conn.Open();
// make two commands here
var commInsert = new OleDbCommand(.....);
var commUpdate = new OleDbCommand(.....);
// here add your parameters with no value
commInsert.Parameters.Add(new OleDbParameter(....));
.......
Foreach (....)
{
Foreach (....)
{
// here only reset the values
commUpdate.Parameters[0].Value = ...
...
int recs = commUpdate.ExecuteNonQuery();
if (recs < 1) // when no records updated do insert
{
commInsert.Parameters[0].Value = iq_question;
.....
}
}
}
commInsert.Dispose();
commUpdate.Dispose();
}
You can also use nested using for commands. Only setting values will be more efficient to what you do right now.

C# How to Retrieve DateSet Value in SqlDataAdapter?

In the development, I intent to retrieve the Index Key from SQL Server Database and apply to the local.sdf database. However, I failed to retrieve the Index Key from SQL Server Database. So, how could i retrieve the value stored in DataSet?
E.g: tableName = "ProductTable", indexName = "IX_product".
Or my SqlDataAdapter doesn't return any value?
P/s: I understand that there are numerous of working tutorial in forum and stackoverflow, unfortunately, i couldn't get it worked.
private void btnGetSchema_Click(object sernder, RoutedEventArgs e)
{
SyncDbSchema();
}
private void SyncDbSchema()
{
// setIndexSchema();
DataSet dsIndex = getIndexSchema();
MessageBox.Show("Table Row Count : " + dsIndex.Tables["tbIndex"].Rows.Count);
for (int i = 0; i < dsIndex.Tables[0].Rows.Count; i++)
{
string tableName = dsIndex.Tables[0].Rows[i]["TableName"].ToString();
string indexName = dsIndex.Tables[0].Rows[i]["IndexName"].ToString();
string indexType = dsIndex.Tables[0].Rows[i]["IndexType"].ToString();
}
}
public DataSet getIndexSchema()
{
SqlConnection conn = new SqlConnection(lblServerCon.Content.ToString());
DataSet dataSet = new DataSet();
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
conn.Open();
sqlDataAdapter = new SqlDataAdapter(String.Format(#"USE SyncServer SELECT T.[name] AS [TableName], I.[name] AS [IndexName],
COL_NAME(T.[object_id], IC.[column_id]) AS [ColumnName], I.[type] AS [IndexType], I.[is_unique] AS [Unique]
FROM sys.tables T INNER JOIN [sys].[indexes] I ON I.[object_id] = T.[object_id]
AND I.[is_primary_key] = '0'
INNER JOIN [sys].[index_columns] IC ON IC.[object_id] = T.[object_id]
AND IC.[index_id] = I.[index_id]"), conn);
sqlDataAdapter.FillSchema(dataSet, SchemaType.Source,"tbIndex");
conn.Close();
return dataSet;
}
The query is perfect working in T-SQL and get the result that i intent to retrieve.
TableName IndexName ColumnName IndexType Unique
tbReport IX_tbReport_SID SalesID 2 0
tbReport IX_tbReport_RID ReportID 2 0
Are you sure that you want to use FillSchema?
Why not just?
adapter.Fill(dataSet);
Of course you can combine them first FillSchema (but why you need it?), next data (just Fill)

Categories

Resources