Linq Statement in Datatable - c#

I'm getting the data of my Datatable into a List but i need to get only the items of a matching date how can i do a Linq statement of my datatable to filter the data on the provided date?
My table Structure is taken from a stored procedure
This is my Code:
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("JoinedRecords", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
DataTable myTable = new DataTable();
myTable.Load(cmd.ExecuteReader());
conn.Close();
for (var rowIndex = 0; rowIndex < myTable.Rows.Count; rowIndex++)
{
var row = myTable.Rows[rowIndex];
var rowValues = new List<string>();
foreach (DataColumn column in myTable.Columns)//Where column.Date.Day == 3
{
rowValues.Add(row[column].ToString());
}
var jsonRow = JsonConvert.SerializeObject(rowValues);
// Write current row
reader.Write(jsonRow);
// Add separating comma
if (rowIndex != myTable.Rows.Count - 1)
reader.WriteLine(",");
}
How can i do this?
There a data in my datatable that has datetime format

Can you try:
var myTable = new DataTable();
var rowValues = myTable.AsEnumerable().Where(r => r.Field<string>("Date") == "3").ToList();
And use a .Select() before the .ToList() to get what you want?
Hard to provide more with an example of the data you have.

var rowValues = new List<String>();
var value = from r in rowValues
where column.Date.Day == 3
select r;

Related

My PrintListView adds my Data, but does not add it all onto 1 row

I am writing a program that involves an PrintListView, I have gotten the Data to show, however each part of the Data is on a different Row. The Image marked as [1] below contains my PrintListView, which shows the Data on each different row, I want this Data to be on 1 row only. I am taking a DataSet, which I then turn into a DataTable. I then add the rows of each DataTable to a List, I have checked this in debug, and it only shows up with 3 values, which is great; but they are not on the same row. The Programming Language is C#.
https://i.stack.imgur.com/XAvEq.png [1]
If you could help, that would be handy.
Many Thanks.
public ObjectListView CreateOLVForSingleColumns(DataSet ds)
{
var olv = new ObjectListView();
olv.ShowGroups = false;
var colHeaders = new List<ColumnHeader>();
var objectList = new List<DataRow>();
//Setting the Column Names of the OLV
var totalOrders = new OLVColumn {AspectName = "Total_Orders", Text = "Total Orders", Width = 250};
var totalOrderValue = new OLVColumn {AspectName = "Total_Order_Value", Text = "Total Order Value", Width = 250};
var totalOrdersNotInvoiced = new OLVColumn {AspectName = "Total_Value_Of_Orders_Not_Invoiced", Text = "Total Order Value Not Invoiced", Width = 250};
colHeaders.AddRange(new ColumnHeader[] {totalOrders, totalOrderValue, totalOrdersNotInvoiced});
olv.Columns.AddRange(colHeaders.ToArray());
var dt = ds.Tables["Total Amount of Orders"];
var dt2 = ds.Tables["Total Value of Orders"];
var dt3 = ds.Tables["Total Value of Orders Not Invoiced"];
var dt4 = new DataTable();
dt4.Merge(dt);
dt4.Merge(dt2);
dt4.Merge(dt3);
for (int i = 1; i <= dt4.Rows.Count; i++)
{
var value = dt4.Rows[0];
var value2 = dt4.Rows[1];
var value3 = dt4.Rows[2];
olv.AddObjects(new DataRow[] { value, value2, value3 });
}
I think your problem is with DataTable.Merge not with ObjectListView.
I would suggest changing your data source so it all comes back in one table (e.g. by using a JOIN if your reading SQL). That said you can accomplish what you want with something like this:
var dt4 = new DataTable();
//add all the columns
foreach (DataColumn c in
dt.Columns.Cast<DataColumn>()
.Union(dt2.Columns.Cast<DataColumn>())
.Union(dt3.Columns.Cast<DataColumn>()))
{
dt4.Columns.Add(c.ColumnName, c.DataType);
}
if(dt.Rows.Count != dt2.Rows.Count|| dt.Rows.Count != dt3.Rows.Count)
throw new Exception("DataTables had different row counts");
for (int i = 0; i < dt.Rows.Count; i++)
{
var row = dt4.Rows.Add();
foreach (DataColumn c in dt.Columns)
if (dt.Rows[i][c] != DBNull.Value)
row[c.ColumnName] = dt.Rows[i][c];
foreach (DataColumn c in dt2.Columns)
if (dt2.Rows[i][c] != DBNull.Value)
row[c.ColumnName] = dt2.Rows[i][c];
foreach (DataColumn c in dt3.Columns)
if (dt3.Rows[i][c] != DBNull.Value)
row[c.ColumnName] = dt3.Rows[i][c];
}
If you run that code with the setup code:
var ds = new DataSet();
var dt = ds.Tables["Total Amount of Orders"] ?? new DataTable();
dt.Columns.Add("A");
dt.Rows.Add("A1");
dt.Rows.Add("A2");
var dt2 = ds.Tables["Total Value of Orders"]?? new DataTable();
dt2.Columns.Add("B");
dt2.Rows.Add("B1");
dt2.Rows.Add("B2");
var dt3 = ds.Tables["Total Value of Orders Not Invoiced"]?? new DataTable();
dt3.Columns.Add("C");
dt3.Rows.Add("C1");
dt3.Rows.Add("C2");
You get
If you use Merge then you get

c# - DataTable expression column using linq

I need to add columns from one datatable to another only if the columns in second datable not exists and also the second datatable has expression column that needs to set value from first datatable column using linq.
I have achieved this using foreach but how to do without foreach in linq ?
DataTable first = new DataTable();
first.Clear();
first.Columns.Add("Name");
first.Columns.Add("Exp");
DataRow _ra = dt1.NewRow();
_ra["Name"] = "Column_1";
_ra["Exp"] = "ExpTarget * Column_3";
first.Rows.Add(_ra);
DataRow _r = dt1.NewRow();
_r["Name"] = "Column_2";
_r["Exp"] = "ExpTarget * Column_3";
first.Rows.Add(_r);
DataRow _r2 = dt1.NewRow();
_r2["Name"] = "Column_3";
_r2["Exp"] = "ExpTarget";
first.Rows.Add(_r2);
DataTable second = new DataTable();
second.Clear();
second.Columns.Add("Column_3",typeof(System.Int16));
second.Columns.Add("ExpTarget",typeof(System.Int16));
DataRow _r21 = table.NewRow();
_r21["Column_3"] = 100;
_r21["ExpTarget"] = 2;
second.Rows.Add(_r21);
Code to add columns & expression is below, i need to avoid foreach linq below for expression column, how to do it without foreach ?
// get all columns from first datatable
string[] col = string.Join(",", first.AsEnumerable().Select(x => x["Name"].ToString()).ToArray()).Split(',').ToArray();
// get all columns and expression from first datatable
List<string> exp = string.Join(",", first.AsEnumerable().Select(x => x["Name"].ToString() + "~" + x["Exp"].ToString()).ToArray()).Split(',').ToList();
List<string[]> list = new List<string[]>();
list.Add(col);
second.Columns.AddRange(list.First().Select(r => second.Columns.Contains(r) ? second.Columns["Dummy"] : new DataColumn(r, typeof(System.Decimal))).ToArray());
exp.ForEach(r =>
{
second.Columns[r.ToString().Split('~')[0].ToString()].Expression = r.ToString().Split('~')[1].ToString();
});

How do i add columns to datatable from rows from another datatable

I have a DataTable called dt which is filled with values from excel.
On line 6 (row) i have my header information
Code i have now
string connString = #"Provider=Microsoft.ACE.OLEDB.16.0;Data Source=C:\Users\thoje\Desktop\stack\forslag.xlsx;" +
#"Extended Properties=""Excel 12.0;HDR=No;""";
DataTable dt = new DataTable();
string sql = #"SELECT * from [Ark1$]";
using (OleDbConnection conn = new OleDbConnection(connString))
{
conn.Open();
using (OleDbCommand cmd = new OleDbCommand(sql, conn))
{
using (OleDbDataReader rdr = cmd.ExecuteReader())
{
dt.Load(rdr);
}
}
}
DataTable dt2 = dt.Clone();
//foreach (DataRow dr in dt.Rows)
//{
for (int i = 5; i <= dt.Rows.Count-1; i++)
{
if (i == 6)
{
DataRow dr = dt2.NewRow();
dr.ItemArray = dt.Rows[i].ItemArray;
dt2.Rows.Add(dr);
}
else if(i >=8)
{
DataRow dr = dt2.NewRow();
dr.ItemArray = dt.Rows[i].ItemArray;
dt2.Rows.Add(dr);
}
}
What i need is:
I want all my data on row 6 to become headers in a new DataTable
All data after line 7 i need to append to this new Datatable with the new headers.
What my code shows:
My code now shows how to do it on a DataTable which is cloned, so therefore i have the wrong headernames.
You don't need to iterate through all rows if you only need 1 of them.
DataTable dtSource = new DataTable();
DataTable dtTarget = new DataTable();
// Get row at index == 6 (7th line as this is a 0-based-index)
var headerRow = dtSource.Rows[6];
// Iterate through all values
foreach(var value in headerRow.ItemArray)
{
// For each value create a column
// and add it to your new dataTable
DataColumn dc = new DataColumn(value.ToString());
dc.Caption = value.ToString();
dtTarget.Columns.Add(dc);
}
using a linq approach might be good:
a pseudo way:
//linq query to select row
var query = from myRow in
myDataTable.AsEnumerable() where myRow.Field<int>("RowNo") == 6
select myRow;
// Create a table from the query DataTable newTable =
query.CopyToDataTable<DataRow>();
Your question is pretty confusing to read, and keeps talking about rows where I'd expect columns etc, but I'll make the following assumptions:
You have an excel file with 5 blank rows and then a row of headers, and then data rows
You've successfully imported this data into a Datatable called dt
You want to end up with a datatable that has the values in row 6 as the column names, and the blank rows removed
Code:
for(int i = 5; i >= 0; i--){
if(i == 5)
{
for(int j = 0; j < dt.Columns.Count; j++)
dt.Columns[j].ColumnName = dt.Rows[i][j].ToString();
}
dt.Rows.RemoveAt(i);
}
You don't need to clone the datatable. Watch out for strings that make for poor column names (containing chars like '[' ) making your life miserable further down the line ..

filter a data table with values from an array c#

I have a delete method, it gets an array of GUIDs and I have a data table... how can I filter the data table so it will only contain thoes GUIDs?
public void delete(Guid[] guidlist)
{
datatable template = ReadTemplateList()
...
}
Thank you!
With Linq to DataSet you can create new DataTable which will have only rows with those Guids:
public void Delete(Guid[] guids)
{
DataTable table = ReadTemplateList()
.AsEnumerable()
.Where(r => guids.Contains(r.Field<Guid>("ColumnName")))
.CopyToDataTable();
// ...
}
Another option (which also will work on old .NET versions) is filtering your table with built-in RowFilter functionality which supports IN filters. Let's assume you are filtering by column named ID:
// Check if guids.Length > 0
StringBuilder filter = new StringBuilder("ID IN (");
foreach (Guid id in guids)
filter.AppendFormat("Convert('{0}','System.Guid'),", id);
filter.Append(")");
DataTable template = ReadTemplateList();
DataView view = template.DefaultView;
view.RowFilter = filter.ToString();
DataTable table = view.ToTable();
You can use LINQ:
public static DataTable DeleteGuidsFromTemplate(Guid[] guidlist)
{
DataTable template = ReadTemplateList();
var rowsWithGuids = from row in template.AsEnumerable()
join guid in guidlist
on row.Field<Guid>("Guid") equals guid
select row;
return rowsWithGuids.CopyToDataTable();
}
If you can't use LINQ since you're lower than NET 3.5:
public static DataTable DeleteGuidsFromTemplate(Guid[] guidlist)
{
DataTable template = ReadTemplateList();
DataTable templateGuids = template.Clone();
foreach(DataRow row in template.Rows)
{
Guid guid = (Guid)row["Guid"];
int index = Array.IndexOf(guidlist, guid);
if (index >= 0)
templateGuids.ImportRow(row);
}
return templateGuids;
}
A solution based on DataTable and DataRows.
//fill the datatable from back end
string connStr = ConfigurationManager.ConnectionStrings["ConsoleApplication1.Properties.Settings.NORTHWNDConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand comm = new SqlCommand("select categoryid,categoryname from Categories order by categoryname");
comm.Connection = conn;
SqlDataReader dr = comm.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
//datatable filter logic
string[] filter = { "1", "2" };
DataTable filteredTable = dt.Clone();
foreach (string str in filter)
{
DataRow[] filteredRows = dt.Select("categoryid="+ str); //search for categoryID
foreach (DataRow dtr in filteredRows)
{
filteredTable.ImportRow(dtr);
}
}
EDIT
Without going in the for loop
DataTable dt = new DataTable();
dt.Load(dr); //fill the datatable with sqldatareader
DataTable filteredTable = dt.Clone();
DataView dv = dt.DefaultView;
dv.RowFilter = "categoryid in (1,2)";
filteredTable = dv.ToTable();

Linq in datatable or data set

I have a list<string> and a DataSet. I need to write a Linq query to get the values from dataset or datatable to check if the values are present in List<string>. Please help me in writing the query to get datas from dataset or datatable
i will use foreach after getting the values to check whether the data is present in list<string>
EDIT:
DataSet dsDuplicate = (DataSet) Session["EventDescription"];
DataTable dt = dsDuplicate.Tables[0];
string cellValue = string.Empty;
for (int rowCount = 0; rowCount < gvEventMechanic.Rows.Count; rowCount++)
{
TextBox textBoxId = (TextBox)gvEventMechanic.Rows[rowCount].Cells[2].FindControl("txtId");
lstStringId.Add(textBoxId.Text);
}
List<string> list = ...
DataTable table = ...
var items = new HashSet<string>(list);
var results = from row in table.AsEnumerable()
where items.Contains(row.Field<string>("YourColumnName"))
select row;
foreach (var matchingRow in results)
{
// do whatever
}
Note: If you need the results to be in the form of another DataTable or DataView (such as for databinding), there are methods for that.
var output = results.CopyToDataTable(); // or
var output = results.AsDataView();

Categories