Separating the column values of DataTable using LINQ - c#

Consider i have a DataTable dt retrieved from oracle database in the following format
Eno | EHobbies | Esal
-------------------------------------------------
1 | Cricket,Tennis,Carroms | 500
2 | Cricket,Volley | 1000
//Datatable for above table
DataTable dt = new DataTable("EmployeeTable");
dt.Columns.Add("Eno", typeof(int));
dt.Columns.Add("EHobbies", typeof(string));
dt.Columns.Add("Esal", typeof(int));
dt.Rows.Add(1, "Cricket,Tennis,Carroms",500 );
dt.Rows.Add(2, "Cricket,Volley",1000);
I need to change this into the following format using linq on the DataTable dt .Need to separate the product column with the help of comma by keeping the other columns same.
Eno | EHobbies | Esal
-------------------------------------
1 | Cricket | 500
1 | Tennis | 500
1 | Carroms | 500
2 | Cricket | 1000
2 | Volleyball | 1000

The following would work:
var newRows = dt.AsEnumerable()
.SelectMany(r => r.Field<string>("EHobbies")
.Split(',')
.Select(x => new { No = r.Field<int>("Eno"),
Hobbies = x,
Sal = r.Field<int>("Esal") }
)
);
DataTable result = new DataTable("EmployeeTable");
result.Columns.Add("Eno", typeof(int));
result.Columns.Add("EHobbies", typeof(string));
result.Columns.Add("Esal", typeof(int));
foreach(var newRow in newRows)
result.Rows.Add(newRow.No, newRow.Hobbies, newRow.Sal);

This also helps:
DataTable newDt = new DataTable();
newDt.Columns.Add("Eno", typeof(int));
newDt.Columns.Add("EHobbies", typeof(string));
newDt.Columns.Add("Esal", typeof(int));
dt.AsEnumerable().ToList()
.ForEach(row => row["EHobbies"].ToString().Split(',').ToList()
.ForEach(item => newDt.Rows.Add(row["Eno"], item, row["Esal"])));

Related

Rearrange DB query result in array for duplicate rows

I want to rearrange query result from db with duplicate data into distinct row (for data display )but having 1 column collect related values in comma separated if more than 1 item found.
For example consider list below (from db query):
ID GROUP DATE
A1212 1 1/1/2019
A1212 2 1/1/2019
A1313 1 3/1/2019
into:
ID GROUP
A1212 1,2
A1313 1
sql string:
select DISTINCT Declaration_Form_Master.*,Declaration_Form_Detail.KPA_Group, Temp_Storage_Reg_V.*,Temp_Storage_Reg_V.ID as TSEID,Users.Company As Uc, 'NULL' as 'CTU_id' from Declaration_Form_Master left outer join Temp_Storage_Reg_V on (Declaration_Form_Master.Master_ID=Temp_Storage_Reg_V.TSEMaster_ID) right join Users on (Declaration_Form_Master.Agent_ID = Users.UserId) right join Declaration_Form_Detail on (Declaration_Form_Master.Master_ID = Declaration_Form_Detail.Master_ID) where Declaration_Form_Master.Confirmation ='1' and Submit_Date >= '2019-01-28' and Submit_Date < '2019-08-30' order by Application_ID DESC
need to join all table because search criteria based on column on multiple table. i cant figure out on sql, but want to rearrange back the result using array or list.
Maybe some algorithm can help.
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(string));
dt.Columns.Add("GROUP", typeof(int));
dt.Columns.Add("DATE", typeof(DateTime));
dt.Rows.Add(new object[] {"A1212", 1, DateTime.Parse("1/1/2019")});
dt.Rows.Add(new object[] {"A1212", 2, DateTime.Parse("1/1/2019")});
dt.Rows.Add(new object[] {"A1213", 1, DateTime.Parse("3/1/2019")});
DataTable dt2 = new DataTable();
dt2.Columns.Add("ID", typeof(string));
dt2.Columns.Add("GROUP", typeof(string));
var groups = dt.AsEnumerable().GroupBy(x => x.Field<string>("ID")).ToList();
foreach (var group in groups)
{
dt2.Rows.Add(new object[] {
group.Key,
string.Join(",", group.Select(x => x.Field<int>("GROUP").ToString()).Distinct())
});
}
}
}
}
If you want to do this action even in T-SQL you must aggregate the result
By exemple
DECLARE #fakeTable TABLE (ID varchar(50), [GROUP] int)
INSERT INTO #fakeTable
VALUES
('A1212', 1 ),
('A1212', 2 ),
('A1213', 1 )
SELECT
ID,
[GROUP] = stuff((
SELECT ','+convert(varchar(100),[GROUP])
FROM #fakeTable innerTable
WHERE innerTable.ID = orgTable.ID
ORDER BY [GROUP]
for xml path (''), type).value('.','nvarchar(max)')
,1,1,'')
FROM (
SELECT DISTINCT ID FROM #fakeTable
) orgTable
More info about aggregation
DataTable dx = new DataTable();
dx.Columns.Add("Application_ID", typeof(int));
dx.Columns.Add("KPA_Group", typeof(int));
foreach(var z in data) {
dx.Rows.Add(new object[] { z.Application_ID,z.KPA_Group });
}
DataTable dt1 = new DataTable();
dt1.Columns.Add("Application_ID", typeof(string));
dt1.Columns.Add("KPA_Group", typeof(string));
var groups = dx.AsEnumerable().GroupBy(x => x.Field<Int32>("Application_ID")).ToList();
foreach (var group in groups)
{
dt1.Rows.Add(new object[] {
group.Key,
string.Join(",", group.Select(x => x.Field<int>("KPA_Group").ToString()).Distinct())
});
}
foreach (DataRow row in dt1.Rows)
{
#:#row["Application_ID"].ToString() |
#:#row["KPA_Group"] <br />
}
result :
2019080001 | 2,3
2019070002 | 2
2019070001 | 2
2019060001 | 1,2
2019040002 | 2
2019030002 | 2
2019030001 | 2
2019020002 | 2
2019020001 | 2
i dont understand why i can't use CopyToDataTable method. solved this by using foreach.

How to find the count of distinct records in a MS Access database using C#?

I have an MS Access database as below
Filing_Year | Name
------------------------
02/01/2008 | AAA
02/01/2008 | AAA
02/03/2008 | AAA
03/01/2008 | BBB
I need a query in C# which will get me an output as below and display it in a gridview
Filing_Year | file_count
----------------------------
02/01/2008 | 2
02/03/2008 | 1
03/01/2008 | 1
This is the code I tried:
dataGridView1.Columns.Add("Column", "FileCount"); // file count is not an element in database
OleDbConnection con = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;DataSource=|DataDirectory|\RMS_Database.mdb");
con.Open();
OleDbDataAdapter sda = new OleDbDataAdapter("select Filing_Year,count(*) from Checklist_Data group by Filing_Year ", con);
DataTable dt = new DataTable();
sda.Fill(dt);
BindingSource bSource = new BindingSource();
bSource.DataSource = dt;
dataGridView1.DataSource = bSource;
sda.Update(dt);
With this I am seeing only unique filing_year, but not the count.
Thanks in advance. Help is really appreciated.
You need to modify your SQL Query like:
SELECT Filing_Year, COUNT(Name) as file_count
FROM Checklist_Data
GROUP BY Filing_Year, Name

Datatable group and pivot

I have a DT with following structure
unit | value | date
-------------------------
A | 2 | 01-01-2000
B | 3 | 01-01-2000
A | 4 | 02-01-2000
I would like to transform it into following
| A | B
---------------------------
01-01-2000 | 2 | 3
02-01-2000 | 4 |
What would be the fastest way to achieve this?
EDIT:
I have implemented a function for pivot, which gives me the following:
| A | B | A
--------------------------------------
value | 2 | 3 | 4
date |01-01-2000|01-01-2000|02-01-2000
But in this case I am missing grouping by columns.
By 'fastest' I mean possibly shortest code to achieve this (LINQ?). Or perhaps pivot can be achieved simultaneously in the same query?
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("unit", typeof(string));
dt.Columns.Add("value", typeof(int));
dt.Columns.Add("date", typeof(DateTime));
dt.Rows.Add(new object[] { "A",2, DateTime.Parse("01-01-2000")});
dt.Rows.Add(new object[] { "B",3, DateTime.Parse("01-01-2000")});
dt.Rows.Add(new object[] { "A",4, DateTime.Parse("02-01-2000")});
string[] uniqueUnits = dt.AsEnumerable().Select(x => x.Field<string>("unit")).Distinct().ToArray();
DataTable dt1 = new DataTable();
dt1.Columns.Add("date", typeof(DateTime));
foreach (string unit in uniqueUnits)
{
dt1.Columns.Add(unit, typeof(int));
}
var groups = dt.AsEnumerable().GroupBy(x => x.Field<DateTime>("date"));
foreach (var group in groups)
{
DataRow newRow = dt1.Rows.Add();
foreach (DataRow row in group)
{
newRow["date"] = group.Key;
newRow[row.Field<string>("unit")] = row.Field<int>("value");
}
}
}
}
}
It's more lines of code but can be done with only one loop as well:
DataTable dt1 = new DataTable();
dt1.Columns.Add(new DataColumn("unit",typeof(string)));
dt1.Columns.Add(new DataColumn("value",typeof(int)));
dt1.Columns.Add(new DataColumn("date",typeof(DateTime)));
dt1.Rows.Add(new object[] { "A", 2, DateTime.Parse("01-01-2000") });
dt1.Rows.Add(new object[] { "B", 3, DateTime.Parse("01-01-2000") });
dt1.Rows.Add(new object[] { "A", 4, DateTime.Parse("02-01-2000") });
DataTable dt2 = new DataTable();
dt2.Columns.Add(new DataColumn("date", typeof(DateTime)));
dt2.PrimaryKey = new DataColumn[] { dt2.Columns["date"], };
List<string> cols = new List<string>();
List<DateTime> ds = new List<DateTime>();
foreach (DataRow dr1 in dt1.Rows)
{
string unit = dr1["unit"].ToString();
if (!cols.Contains(unit))
{
dt2.Columns.Add(new DataColumn(unit, typeof(int)));
cols.Add(unit);
}
DateTime pkDate = (DateTime)dr1["date"];
if (!ds.Contains(pkDate))
{
ds.Add(pkDate);
DataRow dr = dt2.NewRow();
dr["date"] = dr1["date"];
dr[unit] = dr1["value"];
dt2.Rows.Add(dr);
}
else
{
dt2.Rows.Find(pkDate)[unit] = dr1["value"];
}
}

How to edit/update in dynamic table

I have dynamic DataTable says to be DataTable dt=New DataTable(); and column name says to be ID, F_name, L_name.
I had fill a value to this column seems to be
ID | F_name | L_name
1 | mit | jain
2 | raj | patel
3 | anki | patel
4 | alpa | dumadiya
If I want to edit/update column 2 says to be ID=2, F_name that is raj to rajan
what shall I have to do?
You can try like this :
static void Main(string[] args)
{
DataTable dt = GetTable();
DataRow[] dr = dt.Select("ID=2 and F_Name='raj'");
if (dr !=null)
{
foreach (var item in dr)
{
item["F_name"] = "rajan";
}
}
}
static DataTable GetTable()
{
DataTable dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("F_name");
dt.Columns.Add("L_name");
dt.Rows.Add("1", "mit", "jain");
dt.Rows.Add("2", "raj", "patel");
dt.Rows.Add("3", "anki", "patel");
dt.Rows.Add("4", "alpa", "dumadiya");
return dt;
}

Add columns of datatables in a dataset

I have a DataSet with 2 DataTable's. Each DataTable contains a column called "cost".
I want to calculate the sum of all costs for the 2 tables in a table called Result table, like the example below. How can I do that?
Table 1
Name | cost
balan | 6
gt | 5
Table 2
Name | cost
balan | 2
gt | 8
Result table
Name | cost
balan | 8
gt | 12
This is a way to do it:
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
DataTable results = new DataTable();
dt1.Columns.Add("Name");
dt1.Columns.Add("cost", typeof(int));
dt2.Columns.Add("Name");
dt2.Columns.Add("cost", typeof(int));
results.Columns.Add("Name");
results.Columns.Add("cost", typeof(int));
dt1.Rows.Add("balan", 6);
dt2.Rows.Add("balan", 2);
dt1.Rows.Add("gt", 5);
dt2.Rows.Add("gt", 8);
foreach (DataRow dr1 in dt1.Rows)
{
results.Rows
.Add(
dr1["Name"],
(int)dr1["cost"] + (int)dt2.Select(String.Format("Name='{0}'", dr1["name"]))[0]["cost"]
);
}
to get the result, you can do something like
var table1 = yourDataSet.Tables["Table 1"];
var table2 = yourDataSet.Tables["Table 2"];
var results = table1.AsEnumerable().Select(t1 => new {
name = t1.Field<string>("Name"),
cost = t1.Field<int>("cost")
})
.Concat(
table2.AsEnumerable().Select(t2 => new {
name = t2.Field<string>("Name"),
cost = t2.Field<int>("cost")
})
)
.GroupBy(m => m.name)
.Select(g => new {
name = g.Key,
cost = g.Sum(x => x.cost)
});
this won't give you a dataTable, but an IEnumerable. To transform an IEnumerable to a dataTable, see for example here
or easier, if table1 and table2 have same rows
var table1 = yourDataSet.Tables["Table 1"];
var table2 = yourDataSet.Tables["Table 2"];
var results = new DataTable();
results.Columns.Add("Name");
results.Columns.Add("cost", typeof(int));
table1.AsEnumerable().Concat(table2.AsEnumerable())
.GroupBy(m => m.Field<string>("Name"))
.Select(g => results.Rows.Add(g.Key, g.Sum(x => x.Field<int>("cost"))));

Categories

Resources