Get N number of columns from datatable c# - c#

I have a datatable where I need to take n number of columns. For ex: From the below datatable I need to take first 10 columns alone with data and put it in another datatable.
Code:
DataTable dtRecord = DAL.GetRecords();
I tried this and this doesn't take the required column.
var selectColumns = dtRecord .Columns.Cast<System.Data.DataColumn>().Take(10);

You can also use this
private DataTable GetNColumnsFromDataTable(DataTable tblSource, int outputCols)
{
DataTable columnOutput = tblSource.Copy();
if (outputCols > 0 && outputCols < tblSource.Columns.Count)
{
while (outputCols < columnOutput.Columns.Count)
{
columnOutput.Columns.RemoveAt(columnOutput.Columns.Count - 1);
}
}
return columnOutput;
}

You can do it like this:
var selectColumns = dtRecord.Columns.Cast<DataColumn>().Take(10);
var dtResult = new DataTable();
foreach (var column in selectColumns)
dtResult.Columns.Add(column.ColumnName);
foreach (DataRow row in dtRecord.Rows)
dtResult.Rows.Add(row.ItemArray.Take(10).ToArray());
Perhaps you should create a column of the same type and with the same expression:
dtResult.Columns.Add(column.ColumnName, column.DataType, column.Expression);

To copy from one DataTable to another, you can extract the columns of interest
var moveCols = dtRecord.Columns.Cast<DataColumn>().Take(10).Select(c => c.ColumnName).ToArray();
Then you must create new DataColumns in a new table, then create new DataRows in the new table:
var newTable = new DataTable();
foreach (var c in moveCols)
newTable.Columns.Add(c);
foreach (var r in dtRecord.AsEnumerable())
newTable.Rows.Add(moveCols.Select(c => r[c]).ToArray());
Which you can make an extension method on DataTable:
public static DataTable Slice(this DataTable dt, params string[] colnames) {
var newTable = new DataTable();
foreach (var c in colnames)
newTable.Columns.Add(c, dt.Columns[c].DataType);
foreach (var r in dt.AsEnumerable())
newTable.Rows.Add(colnames.Select(c => r[c]).ToArray());
return newTable;
}
Now you can call
var newTable = dtRecord.Slice(moveCols);
With a nice extension method, you can convert from Dictionarys to a DataTable dynamically:
var newTable = dtRecord.AsEnumerable().Select(r => moveCols.ToDictionary(c => c, c => r[c])).AsDataTable();
I have some for converting ExpandoObject and anonymous objects as well, as well as an extension to convert those to anonymous objects dynamically. Here is the code for Dictionarys to DataTable:
public static DataTable AsDataTable(this IEnumerable<IDictionary<string, object>> rows) {
var dt = new DataTable();
if (rows.Count() > 0) {
foreach (var kv in rows.First())
dt.Columns.Add(kv.Key, kv.Value.GetType());
foreach (var r in rows)
dt.Rows.Add(r.Values.ToArray());
}
return dt;
}
public static DataTable AsDataTable(this IEnumerable<Dictionary<string, object>> rows) => ((IEnumerable<IDictionary<string, object>>)rows).AsDataTable();

Get 10 columns:
var tbl = new System.Data.DataTable();
var cols = tbl.Columns.Cast<System.Data.DataColumn>().Take(10);
// if you wish to get first 10 columns...
If you want to get the data, then you have to loop through the columns to get the data.
var data = cols.SelectMany(x => tbl.Rows.Cast().Take(10).Select(y => y[x]));
of course, this will dump all the data into an ienumerable, if you want to use strong typed object or a list of one dimensional array, believe it's fairly simple, for example:
var data2 = cols.Select(x => tbl.Rows.Cast().Take(10).Select(y => y[x]).ToArray());

Related

How to match data from two data tables have single row using LINQ or C# other way

I have two data-table like below getting data from other datatables
DataTable dt
DataTable dt2
Datatable dt have below value and every time dt and dt2 have single row values only then easy match them
F1 F2 F3 F4
Yes No Yes No
Data-table dt2 have below value
F1 F2 F3
Yes Yes Yes
I want to match output like below into Data-table dt3, both on column name
F1 F3
Yes Yes
See datatable dt and datable dt2 both have only one row every time, so you can match dynamic because both have one row only with column name and value, so I not am getting how to match with dynamic using LINQ or some other way for better understanding please check the below image
If without linq is an option then you can try the below method:
public DataTable getMatchedColumnAndValue(DataTable dt1, DataTable dt2)
{
try
{
var ndt = new DataTable();
//creating columns for the table
var dt1columns = dt1.Columns.Cast<DataColumn>().Select(s => s.ColumnName).ToList();
var dt2columns = dt2.Columns.Cast<DataColumn>().Select(s => s.ColumnName).ToList();
var MatchedCol = dt1columns.Intersect(dt2columns).ToList();
foreach (var col in MatchedCol)
{
ndt.Columns.Add(col);
}
//creating columsn matcehd row
var drnew = new string[MatchedCol.Count];
for (int i = 0; i < MatchedCol.Count; i++)
{
if (dt1.Rows[0][MatchedCol[i]].ToString() == dt2.Rows[0][MatchedCol[i]].ToString())
drnew[i] = dt1.Rows[0][MatchedCol[i]].ToString();
else
drnew[i] = null;
}
ndt.Rows.Add(drnew);
//removing null value columns
foreach (var col in MatchedCol)
{
if (ndt.AsEnumerable().All(dr => dr.IsNull(col)))
ndt.Columns.Remove(col);
}
return ndt;
}
catch (Exception ex)
{
throw ex;
}
}
I believe someone might able to do better but here is mine. ※
Simplified the answer a bit.
private static DataTable RegenerateDataTableInCommon(DataTable dt, DataTable dt2)
{
var dtRows = dt.Rows.Cast<DataRow>();
var dt2Rows = dt2.Rows.Cast<DataRow>();
var dtColumnNames = dt.Columns.Cast<DataColumn>().Select(dtC => dtC.ColumnName);
var columnNameMatched = dt2.Columns.Cast<DataColumn>().Select(dtC => dtC.ColumnName).Where(colName => dtColumnNames.Contains(colName));
var cellValueMatched = columnNameMatched.Where(colName => dtRows.First()[colName] == dt2Rows.First()[colName]);
DataTable outDt = new DataTable();
outDt.Clear();
DataRow nRow = outDt.NewRow();
foreach (var colName in cellValueMatched)
{
outDt.Columns.Add(colName);
nRow[colName] = dtRows.First()[colName];
}
outDt.Rows.Add(nRow);
return outDt;
}

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 to add row with value to existing datatable in console Application

I have datatable on which I have to perform filter like where, order by. I have list of customerName. I want to filter data for each customername
I tried below code for same
foreach (string customer in CustName)
{
Datarow[] DataDR = TradeFinanceBF3.Select(TradeFinanceBF3.Columns["Cust_Name"].ColumnName.Trim() + "='A'", "USD equi DESC");
}
I get datarow, then how to pass it to dataTable, and how to pass all customer data to same datatable.
I tried LinkQuery Also to filter data as below
foreach (string customer in CustName)
{
DataTable selectedTable = TradeFinanceBF3.AsEnumerable()
.Where(r => r.Field<string>("Cust_Name") == customer)
.OrderByDescending(r => r.Field<double>("IndexABC"))
.CopyToDataTable();
///Datable OutPut= ?????
}
I got datatable, But then how to add all customer data to one datatable?
You could do something like this:
DataRow[] result = TradeFinanceBF3.Select("Cust_Name ='A'", "USD equi DESC");
DataTable aux = TradeFinanceBF3.Clone();
foreach (DataRow record in result)
{
aux.ImportRow(record);
}
I hope it will fix your issue
[Test]
public void GetCustomerData()
{
DataTable TradeFinanceBF3 = GetTable();
DataTable NewDatatable = TradeFinanceBF3.Clone();
IList<string> CustName = new List<string> { "Janet", "David" };
var selectedTable = (from dataRow in TradeFinanceBF3.AsEnumerable()
join customerName in CustName on dataRow.Field<string>("Cust_Name") equals customerName
select new
{
CustName = dataRow["Cust_Name"],
IndexABC = dataRow["IndexABC"]
}).OrderByDescending(p=>p.IndexABC);
foreach (var table in selectedTable)
{
NewDatatable.Rows.Add(table.CustName, table.IndexABC);
}
Console.Write(NewDatatable);
}
private DataTable GetTable()
{
// Here we create a DataTable with four columns.
DataTable table = new DataTable();
table.Columns.Add("Cust_Name", typeof(string));
table.Columns.Add("IndexABC", typeof(double));
// Here we add five DataRows.
table.Rows.Add("David", 1);
table.Rows.Add("Sam", 2);
table.Rows.Add("Christoff",2);
table.Rows.Add("Janet", 4);
table.Rows.Add("Melanie", 6);
return table;
}

How to convert linq result to DataTable

I have the following DataTable:
DataTable itemsOnSkid = new DataTable();
itemsOnSkid.Columns.Add("ItemNumber");
itemsOnSkid.Columns.Add("Qty");
And I need to aggregate this datatable by itemnumber. I'm using the following linq code:
var result = from row in itemsOnSkid.AsEnumerable()
group row by row.Field<string>("ItemNumber") into grp
select new
{
ItemNumber = grp.Key,
Qty = grp.Sum(r => r.Field<int>("Qty"))
};
Problem is that I need to replace the first datatable with this result, but I'm not able to use .CopyToDataTable() on result.
How can I convert this result back to a datatable?
You can't use CopyToDataTable() in this case, since the thing you're copying from has to be a DataRow. I think you're stuck doing it manually.
DataTable items = new DataTable();
items.Columns.Add("number");
items.Columns.Add("qty");
var result = from r in items.AsEnumerable()
group r by r.Field<string>("number") into grp
select new {
number = grp.Key,
qty = grp.Sum(r => r.Field<int>("qty"))
};
DataTable newItems = new DataTable();
newItems.Columns.Add("number");
newItems.Columns.Add("qty");
foreach (var item in result) {
DataRow newRow = newItems.NewRow();
newRow["number"] = item.number;
newRow["qty"] = item.qty;
newItems.AddRow(newRow);
}
I have tried fast the same as TFischer, but using directly a DataRow. No extra object.
This is my Code:
private static void Main(string[] args)
{
var itemsOnSkid = CreateDataTable();
FillData(itemsOnSkid);
var result = itemsOnSkid.AsEnumerable().GroupBy(row => row.Field<string>("ItemNumber")).Select(
grp =>
{
var newRow = itemsOnSkid.NewRow();
newRow["ItemNumber"] = grp.Key;
newRow["Qty"] = grp.Sum(r => r.Field<int>("Qty"));
return newRow;
}).CopyToDataTable();
}
private static DataTable CreateDataTable()
{
var itemsOnSkid = new DataTable();
itemsOnSkid.Columns.Add("ItemNumber");
itemsOnSkid.Columns.Add("Qty", typeof(int));
return itemsOnSkid;
}
// Fill some Data in the Table
private static void FillData(DataTable itemsOnSkid)
{
for (int i = 1; i <= 10; i++)
{
var newRow = itemsOnSkid.NewRow();
newRow["ItemNumber"] = i % 3;
newRow["Qty"] = i;
itemsOnSkid.Rows.Add(newRow);
}
}
I Hope it helps.
var query = from empl in te.Employees.AsEnumerable() select empl;
List<Employee> dt = query.ToList();
gdempdetails.DataSource = dt;
gdempdetails.DataBind();
Here's a simpler way to do this
// Create the table if you don't already have it
// Otherwise ignore this part
DataTable newItems = new DataTable();
newItems.Columns.Add("number");
newItems.Columns.Add("qty");
// LINQ query
IEnumerable<DataRow> result = from row in itemsOnSkid.AsEnumerable()
group row by row.Field<string>("ItemNumber") into grp
select newItems.LoadDataRow(new object[]
{
ItemNumber = grp.Key,
Qty = grp.Sum(r => r.Field<int>("Qty"))
}, false);
// Copy rows to DataTable
newItems = result.CopyToDataTable<DataRow>();

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