I am want to get a specific row from a dataset, not the entire row but only specifics column from the row
it's should be something like that:
dataRow datarow1 = myDataSet.Tables["table1"].Column["column3
and column4"].Select(column1='1' and column2='specificvalue');
someone can help me?
Slightly different syntax:
var result = from row in set.Tables["table1"].AsEnumerable()
where row.Field<int>("column1") == 1 &&
row.Field<string>("column2") == "specificValue"
select new { Column3 = row.Field<string>("Column3"),
Column4 = row.Field<string>("Column4") };
My best guess:
var datarows = myDataSet.Tables["table1"].AsEnumerable()
.Where(x=> x.Field<int>("col1") == 1 && x.Field<string>("col2") == "specificvalue")
.Select(x=>new
{
col3 = x.Field<int>("col3"),
col4 = x.Field<int>("col4")
})
.ToList();
Related
I've been trying to convert the following the code from VB to C#:
Dim rowsnotfound As DataRow() = (From rowstb2 As DataRow In dsNew.Tables("parts").Rows.OfType(Of DataRow)() Where (Aggregate rowstb1 As DataRow In dsOld.Tables("parts").Rows.OfType(Of DataRow)() Where ((rowstb1.Item("TRANSACTION")) = (rowstb2.Item("TRANSACTION")) And (rowstb1.Item("DESCRIPTION")) = (rowstb2.Item("DESCRIPTION")) And (rowstb1.Item("QTY")) = (rowstb2.Item("QTY")) And (rowstb1.Item("PART_NUM")) = (rowstb2.Item("PART_NUM"))) Into Count()) = 0).ToArray
I know this will appear as a long strand of code on the computer so here is a snippet of the aggregate portion of the code so you can read it easier:
(Aggregate rowstb1 As DataRow In dsOld.Tables("parts").Rows.OfType(Of DataRow)() Where ((rowstb1.Item("TRANSACTION")) = (rowstb2.Item("TRANSACTION")) And (rowstb1.Item("DESCRIPTION")) = (rowstb2.Item("DESCRIPTION")) And (rowstb1.Item("QTY")) = (rowstb2.Item("QTY")) And (rowstb1.Item("PART_NUM")) = (rowstb2.Item("PART_NUM"))) Into Count())
I researched the aggregate clause and know the basics of how it functions. However, I am having a tremendous amount of trouble converting it to C#. Any help will be greatly appreciated.
What you are doing appears to be equivalent of a SQL LEFT JOIN operation where you want to find elements in the First collection that are not in the Second. You can do this with out having to use an aggregate by using the following:
IEnumerable<DataRow> newRows = dsNew.Tables["parts"].Rows.OfType<DataRow>();
IEnumerable<DataRow> oldRows = dsOld.Tables["parts"].Rows.OfType<DataRow>();
DataRow[] rowsNotFound = newRows
.GroupJoin(oldRows,
o => new
{
Transaction = o.Field<int>("TRANSACTION"),
Description = o.Field<string>("DESCRIPTION"),
Quantity = o.Field<int>("QTY"),
PartNumber = o.Field<string>("PART_NUM")
},
i => new
{
Transaction = i.Field<int>("TRANSACTION"),
Description = i.Field<string>("DESCRIPTION"),
Quantity = i.Field<int>("QTY"),
PartNumber = i.Field<string>("PART_NUM")
},
(o, i) => new {NewRow = o, OldRows = i})
.SelectMany(g => g.OldRows.DefaultIfEmpty(), (g, oldRow) => oldRow == null ? g.NewRow : null)
.Where(r => r != null)
.ToArray();
I didn't know the data types so I guessed based on the field names.
I think it'll be something like:
DataRow[] rowsnotfound = (
from DataRow rowstb2 in dsNew.Tables("parts").Rows.OfType<DataRow>()
where ((
from DataRow rowstb1 in dsOld.Tables("parts").Rows.OfType<DataRow>()
where (rowstb1["TRANSACTION"] == rowstb2["TRANSACTION"]
&& rowstb1["DESCRIPTION"] == rowstb2["DESCRIPTION"]
&& rowstb1["QTY"] == rowstb2["QTY"]
&& rowstb1["PART_NUM"] == rowstb2["PART_NUM"])
select rowstb1).Count()) == 0).ToArray();
I have a DataTable with multiple columns. If the value of certain column repeats, I need to remove that row and add the quantities against it. For example, following datatable
ITEM QTY
------------
1 20
2 10
2 10
3 20
would become:
ITEM QTY
-----------
1 20
2 20
3 20
This is what I did
var table = dt.AsEnumerable()
.GroupBy(row => row.Field("ITEM"))
.Select(group => group.First())
.CopyToDataTable();
It removes the extra row but doesn't add up the quantities. So please help me in this regard.
You can use Sum. You just have to find the duplicate-rows first:
var dupGroups = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("ITEM"))
.Where(g => g.Count() > 1);
Now you can use them to get the sum and to remove the redundant rows from the table.
foreach (var group in dupGroups)
{
DataRow first = group.First();
int sum = group.Sum(r => r.Field<int>("QTY"));
first.SetField("QTY", sum);
foreach (DataRow row in group.Skip(1))
dt.Rows.Remove(row);
}
Or in one query which creates a new DataTable.
DataTable newTable = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("ITEM"))
.Select(g =>
{
DataRow first = g.First();
if (g.Count() > 1)
{
int sum = g.Sum(r => r.Field<int>("QTY"));
first.SetField("QTY", sum);
}
return first;
})
.CopyToDataTable();
However, even the second approach modifies the original table which might be undesired since you use CopyToDatatable to create a new DataTable. You need to clone the original table(DataTable newTable = dt.Clone();) to get an empty table with the same schema. Then use NewRow + ItemArray.Clone() or table.ImportRow to create a real clone without modifying the original data.
See: C# simple way to copy or clone a DataRow?
Edit: Here is an example how you can create a clone without touching the original table:
DataTable newTable = dt.Clone();
var itemGroups = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("ITEM"));
foreach (var group in itemGroups)
{
DataRow first = group.First();
if (group.Count() == 1)
newTable.ImportRow(first);
else
{
DataRow clone = newTable.Rows.Add((object[])first.ItemArray.Clone());
int qtySum = group.Sum(r => r.Field<int>("QTY"));
clone.SetField("QTY", qtySum);
}
}
var table = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("ITEM"))
.Select(group => {
var row = group.First();
row['QTY'] = group.Sum(x => x.Field<int>('QTY'));
return row;
}).CopyToDataTable();
This won't change your original DataTable:
var table = dt.Copy().AsEnumerable()
.GroupBy(row=>row["ITEM"])
.Select(g=> {
DataRow dr = g.First();
dr.SetField("QTY", g.Sum(x=>x.Field<int>("QTY")));
return dr;
})
.CopyToDataTable();
I have two DataTables and I want to select the rows from the first one which are not present in second one
For example:
Table A
id column
1 data1
2 data2
3 data3
4 data4
Table B
id column
1 data10
3 data30
I want the result to be:
Table C
id column
2 data2
4 data4
You can use Linq, especially Enumerable.Except helps to find id's in TableA that are not in TableB:
var idsNotInB = TableA.AsEnumerable().Select(r => r.Field<int>("id"))
.Except(TableB.AsEnumerable().Select(r => r.Field<int>("id")));
DataTable TableC = (from row in TableA.AsEnumerable()
join id in idsNotInB
on row.Field<int>("id") equals id
select row).CopyToDataTable();
You can also use Where but it'll be less efficient:
DataTable TableC = TableA.AsEnumerable()
.Where(ra => !TableB.AsEnumerable()
.Any(rb => rb.Field<int>("id") == ra.Field<int>("id")))
.CopyToDataTable();
I got a solution which works without LINQ:
public DataTable CompareDataTables(DataTable first, DataTable second)
{
first.TableName = "FirstTable";
second.TableName = "SecondTable";
//Create Empty Table
DataTable table = new DataTable("Difference");
try
{
//Must use a Dataset to make use of a DataRelation object
using (DataSet ds = new DataSet())
{
//Add tables
ds.Tables.AddRange(new DataTable[] { first.Copy(), second.Copy() });
//Get Columns for DataRelation
DataColumn[] firstcolumns = new DataColumn[ds.Tables[0].Columns.Count];
for (int i = 0; i < firstcolumns.Length; i++)
{
firstcolumns[i] = ds.Tables[0].Columns[i];
}
DataColumn[] secondcolumns = new DataColumn[ds.Tables[1].Columns.Count];
for (int i = 0; i < secondcolumns.Length; i++)
{
secondcolumns[i] = ds.Tables[1].Columns[i];
}
//Create DataRelation
DataRelation r = new DataRelation(string.Empty, firstcolumns, secondcolumns, false);
ds.Relations.Add(r);
//Create columns for return table
for (int i = 0; i < first.Columns.Count; i++)
{
table.Columns.Add(first.Columns[i].ColumnName, first.Columns[i].DataType);
}
//If First Row not in Second, Add to return table.
table.BeginLoadData();
foreach (DataRow parentrow in ds.Tables[0].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r);
if (childrows == null || childrows.Length == 0)
table.LoadDataRow(parentrow.ItemArray, true);
}
table.EndLoadData();
}
}
}
For more Visit http://microsoftdotnetsolutions.blogspot.in/2012/12/compare-two-datatables.html
You can use Linq Enumerable.Except Method function to get diffence between two DataTable's Here i use firstDt and secondDt,remember both Dt's have the same structure.
var EntriesNotInB = firstDt.AsEnumerable().Select(r => r.Field<string>("abc")).Except(secondDt.AsEnumerable().Select(r => r.Field<string>("abc")));
if (EntriesNotInB.Count() > 0)
{
DataTable dt = (from row in firstDt.AsEnumerable()join id in EntriesNotInB on row.Field<string>("abc") equals id select row).CopyToDataTable();
foreach (DataRow row in dt.Rows)
{
/////Place your code to manipulate on datatable Rows
}
}
To read more on Enumerable.Except Method,Go to http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except(v=vs.110).aspx
and its Done!!!! Happy Coding.........
I am using this below:
public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2)
{
using (DataTable targetTable = dt1.Clone())
{
var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc =>
new DataColumn(dc.ColumnName, dc.DataType, dc.Expression,
dc.ColumnMapping));
var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
where targetTable.Columns
.Contains(dc.ColumnName) == false
select dc;
targetTable.Columns.AddRange(dt2FilterQuery.ToArray());
var rowData = from row1 in dt1.AsEnumerable()
join row2 in dt2.AsEnumerable()
on row1.Field<int>("Code") equals
row2.Field<int>("Code")
select row1.ItemArray
.Concat(row2.ItemArray
.Where(r2 =>
row1.ItemArray.Contains(r2) == false)).ToArray();
foreach (object[] values in rowData) targetTable.Rows.Add(values);
return targetTable;
}
}
There is a problem with this line:
select row1.ItemArray.Concat(row2.ItemArray.Where(r2 =>
row1.ItemArray.Contains(r2) == false)).ToArray();
It seems to be saying don't include me if this value (rather than column) already exists.
I am using this method to join two tables together based on a column that both tables share, but I only want the unique columns with data of both tables as a final result.
Any ideas?
I am not sure if I understand your requirement 100%, but this:
row2.ItemArray.Where(r2 => row1.ItemArray.Contains(r2) == false)
will filter out those items that happen to appear in any column of table 1, not just the column you are joining on.
So what I would try to do is filter the item based on the index, using an overload of the Where extension method:
// Get the index of the column we are joining on:
int joinColumnIndex = dt2.Columns.IndexOf("Code");
// Now we can filter out the proper item in the rowData query:
row2.ItemArray.Where((r2,idx) => idx != joinColumnIndex)
...
No, wait. Here:
var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
where targetTable.Columns
.Contains(dc.ColumnName) == false
select dc;
You are filtering out all columns of table 2 whose name also appear in table 1. So what you probably want is this:
public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2)
{
DataTable targetTable = dt1.Clone();
var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc =>
new DataColumn(dc.ColumnName, dc.DataType, dc.Expression,
dc.ColumnMapping));
var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
where !targetTable.Columns.Contains(dc.ColumnName)
select dc;
var columnsToAdd = dt2FilterQuery.ToArray();
var columnsIndices = columnsToAdd.Select(dc => dt2.Columns.IndexOf(dc.ColumnName));
targetTable.Columns.AddRange(columnsToAdd);
var rowData = from row1 in dt1.AsEnumerable()
join row2 in dt2.AsEnumerable()
on row1.Field<int>("Code") equals
row2.Field<int>("Code")
select row1.ItemArray
.Concat(row2.ItemArray
.Where((r2,idx) =>
columnsIndices.Contains(idx))).ToArray();
foreach (object[] values in rowData) targetTable.Rows.Add(values);
return targetTable;
}
Btw. I don't quite understand why you are wrapping the DataTable you return in a using statement. Imho it is kind of pointless to dispose the very object you return to your caller right away...
I have a linq list. I would like to select a certain row. Do I have to do a foreach to loop thru the rows to get to the specified row, or is there another way.
What I dont want...
EDIT
specifiedRow = 13;
-
var linqList = from a in random.List
where (a.id == idNum)
select new {a.id, a.name, a.address};
int counter = 0;
foreach (var item in linqList) {
if(counter == specifiedRow) {
//do stuff
}
}
What I would like...
var linqList = from a in random.List
where (a.id == idNum)
//row is specified row in linqList
select new {a.id, a.name, a.address};
linqList.Skip(specifiedRow -1).FirstOrDefault()
That should give you the item you want, or null if there weren't enough rows.
If you know the row number that you're after then you can use the Skip() method
Eg to get the 6th row:
var linqList = from a in random.List
where (a.id == idNum)
Skip(5)
select new {a.id, a.name, a.address};
You can use:
random.List.Where(a => a.id == idNum).Select(a => new {a.id, a.name, a.address}).ElementAt(counter);