how to DataTable split into mutiple datatables c# - c#

Gender Age Category
--------------------------------
Male | 10 | 2
Female | 15 | 1
Trans | 13 | 3
Female | 10 | 1
Male | 20 | 2
i have a datatable with above values. Male CategoryId is 2. in above table there are total 2 Males rows. based on Category, merged two rows and divide into a seperate datatable.
My required output is :-
Datatable 1
Gender Age Category
--------------------------------
Male | 10 | 2
Male | 20 | 2
DataTable 2
Gender Age Category
--------------------------------
Female | 15 | 1
Female | 10 | 1
DataTable 3
Gender Age Category
--------------------------------
Trans | 13 | 3

var view = sourceDataTable.DefaultView;
view.RowFilter = "Category = 2";
var maleDataTable = view.ToTable();
view.RowFilter = "Category = 1";
var femaleDataTable = view.ToTable();
view.RowFilter = "Category = 3";
var transDataTable = view.ToTable();

Here you go:
List<DataTable> result = DTHead.AsEnumerable()
.GroupBy(row => row.Field<DataType>("Category"))
.Select(g => g.CopyToDataTable())
.ToList();
For more details please check this post:Split Tables

See following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication48
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Gender", typeof(string));
dt.Columns.Add("Age", typeof(int));
dt.Columns.Add("Category", typeof(int));
dt.Rows.Add(new object[] {"Male", 10, 2});
dt.Rows.Add(new object[] {"Female", 15, 1});
dt.Rows.Add(new object[] {"Trans", 13, 3});
dt.Rows.Add(new object[] {"Female", 10, 1});
dt.Rows.Add(new object[] {"Male", 20, 2});
DataTable dt1 = dt.AsEnumerable().Where(x => x.Field<string>("Gender") == "Male").CopyToDataTable();
DataTable dt2 = dt.AsEnumerable().Where(x => x.Field<string>("Gender") == "Feale").CopyToDataTable();
DataTable dt3 = dt.AsEnumerable().Where(x => x.Field<string>("Gender") == "Trans").CopyToDataTable();
}
}
}
Here is a more generic solution that get every type in a column :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication48
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Gender", typeof(string));
dt.Columns.Add("Age", typeof(int));
dt.Columns.Add("Category", typeof(int));
dt.Rows.Add(new object[] { "Male", 10, 2 });
dt.Rows.Add(new object[] { "Female", 15, 1 });
dt.Rows.Add(new object[] { "Trans", 13, 3 });
dt.Rows.Add(new object[] { "Female", 10, 1 });
dt.Rows.Add(new object[] { "Male", 20, 2 });
//updated code
string[] rowNames = dt.AsEnumerable().Select(x => x.Field<string>("Gender")).Distinct().ToArray();
DataSet ds = new DataSet();
foreach (string gender in rowNames)
{
DataTable newDt = dt.AsEnumerable().Where(x => x.Field<string>("Gender") == gender).CopyToDataTable();
newDt.TableName = gender;
ds.Tables.Add(newDt);
}
}
}
}

Related

c# LINQ query from master and masterdetail table

I have two tables.
One is Master
Id
Date
1
2022-03-12
2
2022-02-14
3
2021-10-15
4
2021-04-09
5
2020-06-24
Another one is Detail
Id
MasterId
Name
Quantity
1
1
item1
25
2
1
item2
30
3
1
item3
20
4
2
item1
25
5
2
item2
20
6
3
item1
35
7
4
item4
25
8
5
item1
25
9
5
item3
29
From above two table I need a query which will give me 3rd table
Year
item1
item2
item3
item4
2020
25
0
29
0
2021
35
0
0
25
2022
50
50
20
0
You want a pivot table
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication18
{
class Program
{
public static void Main(String[] args)
{
DataTable masterTable = new DataTable("Master");
masterTable.Columns.Add("Id", typeof(int));
masterTable.Columns.Add("Date", typeof(DateTime));
masterTable.Rows.Add(new object[] { 1, DateTime.Parse("2022-03-12") });
masterTable.Rows.Add(new object[] { 2, DateTime.Parse("2022-02-14") });
masterTable.Rows.Add(new object[] { 3, DateTime.Parse("2021-10-15") });
masterTable.Rows.Add(new object[] { 4, DateTime.Parse("2021-04-09") });
masterTable.Rows.Add(new object[] { 5, DateTime.Parse("2020-06-24") });
DataTable detailTable = new DataTable("Detail");
detailTable.Columns.Add("Id", typeof(int));
detailTable.Columns.Add("IMasterId", typeof(int));
detailTable.Columns.Add("Name", typeof(string));
detailTable.Columns.Add("Quantity", typeof(int));
detailTable.Rows.Add(new object[] { 1, 1, "item1", 25 });
detailTable.Rows.Add(new object[] { 2, 1, "item2", 30 });
detailTable.Rows.Add(new object[] { 3, 1, "item3", 20 });
detailTable.Rows.Add(new object[] { 4, 2, "item1", 25 });
detailTable.Rows.Add(new object[] { 5, 2, "item2", 20 });
detailTable.Rows.Add(new object[] { 6, 3, "item1", 35 });
detailTable.Rows.Add(new object[] { 7, 4, "item4", 25 });
detailTable.Rows.Add(new object[] { 8, 5, "item1", 25 });
detailTable.Rows.Add(new object[] { 9, 5, "item3", 29 });
string[] items = detailTable.AsEnumerable().Select(x => x.Field<string>("Name")).OrderBy(x => x).Distinct().ToArray();
DataTable pivot = new DataTable("Pivot");
pivot.Columns.Add("Year", typeof(int));
foreach (string item in items)
{
pivot.Columns.Add(item, typeof(int));
}
var joinTable = (from m in masterTable.AsEnumerable().OrderBy(x => x.Field<DateTime>("Date"))
join d in detailTable.AsEnumerable() on m.Field<int>("Id") equals d.Field<int>("Id")
select new {id = m.Field<int>("Id"), year = m.Field<DateTime>("Date").Year, d = d}
).GroupBy(x => x.year).ToList();
foreach (var date in joinTable)
{
DataRow row = pivot.Rows.Add();
row["Year"] = date.Key;
var names = date.GroupBy(x => x.d.Field<string>("Name")).Select(x => new {name = x.Key, quant = x.Sum(y => y.d.Field<int>("Quantity"))});
foreach (var name in names)
{
row[name.name] = name.quant;
}
}
}
}
}

One column GridView data to multiple chart series

I want to create a chart having multiple series from same gridview column.
My GridView data (from Stored Procedure):
Name | Month | Volume
A | 2019-01 | 1400
B | 2019-01 | 1100
B | 2019-02 | 400
C | 2019-01 | 6500
B | 2019-03 | 6500
A | 2019-02 | 500
C | 2019-02 | 35
And I would like to add a Chart with Volume/Name on the axes and seperate series for each month like one serie for 2019-01, another for 2019-02.
For the example above I'll have three series.
I'm very new to ASP.NET and I'll be glad for any clue how I can achive that. Thanks in advance for your help!
You first have to group the data by months. I did that in code below by creating a pivot table and grouping the data by Names.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication106
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Month", typeof(DateTime));
dt.Columns.Add("Volume", typeof(int));
dt.Rows.Add(new object[] {"A", DateTime.ParseExact("2019-01", "yyyy-MM", System.Globalization.CultureInfo.InvariantCulture), 1400});
dt.Rows.Add(new object[] { "B", DateTime.ParseExact("2019-01", "yyyy-MM", System.Globalization.CultureInfo.InvariantCulture), 1100 });
dt.Rows.Add(new object[] { "B", DateTime.ParseExact("2019-02", "yyyy-MM", System.Globalization.CultureInfo.InvariantCulture), 400 });
dt.Rows.Add(new object[] { "C", DateTime.ParseExact("2019-01", "yyyy-MM", System.Globalization.CultureInfo.InvariantCulture), 6500 });
dt.Rows.Add(new object[] { "B", DateTime.ParseExact("2019-03", "yyyy-MM", System.Globalization.CultureInfo.InvariantCulture), 6500 });
dt.Rows.Add(new object[] { "A", DateTime.ParseExact("2019-02", "yyyy-MM", System.Globalization.CultureInfo.InvariantCulture), 500 });
dt.Rows.Add(new object[] { "C", DateTime.ParseExact("2019-02", "yyyy-MM", System.Globalization.CultureInfo.InvariantCulture), 35 });
DateTime[] dates = dt.AsEnumerable().Select(x => x.Field<DateTime>("Month")).Distinct().OrderBy(x => x).ToArray();
DataTable pivot = new DataTable();
pivot.Columns.Add("Name", typeof(string));
foreach (DateTime date in dates)
{
pivot.Columns.Add(date.ToString("yyyy-MM"), typeof(int));
}
var groups = dt.AsEnumerable().GroupBy(x => x.Field<string>("Name")).ToList();
foreach(var group in groups)
{
DataRow newRow = pivot.Rows.Add();
newRow["Name"] = group.Key;
foreach(DataRow row in group)
{
newRow[row.Field<DateTime>("Month").ToString("yyyy-MM")] = row.Field<int>("Volume");
}
}
}
}
}

How can I get the nested rows ordered by nesting level?

I have the following table with attributes: Id, ParentId, Name etc.
The table contains a nesting level as: Objects contain Elements that contain Components).
Id | Parent | Name
---------------------------------------
1 | NULL | Name (this is object 1)
2 | 1 | Name (this is element 1)
3 | 2 | Name (this is component 1)
4 | 2 | Name (this is component 2)
5 | 2 | Name (this is component 3)
6 | 1 | Name (this is element 2)
7 | 6 | Name (this is component 4)
8 | 1 | Name (this is element 3)
9 | NULL | Name (this is object 2)
10 | 9 | Name (this is element 4)
11 | 10 | Name (this is component 5)
12 | 10 | Name (this is component 6)
I need a single LINQ query that handles this result as in the presented table.
I would not like to use nested for loops to get the objects, then for each object to get its elements, then for each element to get its components - the same is for recursion on the table and I do not want this.
Not appropriate for one linq statement. Use a recursive method :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Parent", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Rows.Add(new object[] { 1, null, "Name (this is object 1)" });
dt.Rows.Add(new object[] { 2, 1, "Name (this is element 1)" });
dt.Rows.Add(new object[] { 3, 2, "Name (this is component 1)" });
dt.Rows.Add(new object[] { 4, 2, "Name (this is component 2)" });
dt.Rows.Add(new object[] { 5, 2, "Name (this is component 3)" });
dt.Rows.Add(new object[] { 6, 1, "Name (this is element 2)" });
dt.Rows.Add(new object[] { 7, 6, "Name (this is component 4)"});
dt.Rows.Add(new object[] { 8, 1, "Name (this is element 3)" });
dt.Rows.Add(new object[] { 9, null, "Name (this is object 2)" });
dt.Rows.Add(new object[] { 10, 9, "Name (this is element 4)" });
dt.Rows.Add(new object[] { 11, 10, "Name (this is component 5)" });
dt.Rows.Add(new object[] { 12, 10, "Name (this is component 6)" });
Node.RecursiveFill(dt, null, Node.root);
}
}
public class Node
{
public static Node root = new Node();
public List<Node> children { get; set; }
public int id { get; set; }
public string name { get; set; }
public static void RecursiveFill(DataTable dt, int? parentId, Node parentNode)
{
foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int?>("Parent") == parentId))
{
Node newChild = new Node();
if (parentNode.children == null) parentNode.children = new List<Node>();
parentNode.children.Add(newChild);
newChild.id = row.Field<int>("Id");
newChild.name = row.Field<string>("Name");
RecursiveFill(dt, newChild.id, newChild);
}
}
}
}

How to combine two or more DataTables dynamically in c#

I have two DataTables being filled.
DT1 and DT2
Each DataTable has the same column headers. However, DT2 may or may not have the same amount of rows.
ID | Type | Value
I need the new Table to add Rows as necessary based on the number of results that are returned in the "Type" column and set DT3 rows ID = DT1.ID and Value to "N/A"
DT1 DT2 DT3
ID | Type | Value ID | Type | Value ID | Type | Value
1 ItemCost 5000 27 ItemCost 3800 27 ItemCost 3800
2 TravCost 5700 28 TravCost 4851 28 TravCost 4851
3 UpCharge 3600 3 UpCharge N/A
4 TaxCost 7000 4 TaxCost N/A
Here is my code for this issue:
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID");
dt1.Columns.Add("Type");
dt1.Columns.Add("Value");
dt1.Rows.Add(new Object[] { "1", "ItemCost", "5000" });
dt1.Rows.Add(new Object[] { "2", "TravCost", "5700" });
dt1.Rows.Add(new Object[] { "3", "UpCharge", "3600" });
dt1.Rows.Add(new Object[] { "4", "TaxCost", "7000" });
DataTable dt2 = new DataTable();
dt2.Columns.Add("ID");
dt2.Columns.Add("Type");
dt2.Columns.Add("Value");
dt2.Rows.Add(new Object[] { "27", "ItemCost", "3800" });
dt2.Rows.Add(new Object[] { "28", "TravCost", "4851" });
DataTable dt3 = new DataTable();
dt3 = dt2.Clone();
foreach (DataRow item in dt2.Rows)
{
dt3.Rows.Add(new object[] { item["ID"], item["Type"], item["Value"] });
}
foreach (DataRow item in dt1.Rows)
{
DataRow[] drs = dt3.Select("Type='" + item["Type"].ToString() + "'");
if (drs.Count() == 0)
{
dt3.Rows.Add(new object[] { item["ID"], item["Type"], "N/A" });
}
}

SQL display table in vertical

I am using C# and MySQL as (DBMS) I want to rotate my table. this is my query :
SELECT p.gender,Count(CASE WHEN disease like '%Anemia%' THEN 1 END) AS 'Anemia'
,Count(CASE WHEN disease like '%Injuries%' THEN 1 END) AS 'Injuries'
FROM phc_db.record r, phc_db.patient p
where r.malteser_id=p.malteser_id
group by p.gender
The result is :
Gender Anemia Injuries
------------------------
Female 1 0
Male 2 1
------------------------
And I want :
Disease Male Female
----------------------
Anemia 2 1
Injuries 1 0
----------------------
Any Idea? Any Suggestion?
Thanks
You can try pivoting on the disease instead of the gender. In this case, the genders become columns.
SELECT
disease,
SUM(CASE WHEN p.gender = 'Male' THEN 1 END) AS Male,
SUM(CASE WHEN p.gender = 'Female' THEN 1 END) AS Female
FROM phc_db.record r
INNER JOIN phc_db.patient p
ON r.malteser_id = p.malteser_id
GROUP BY disease
WHERE disease IN ('Anemia', 'Injuries')
Note that from your current output it appears that you may not need to use LIKE to match diseases. In my query above, I check for the exact disease names of anemia and injuries. If I assumed wrongly, then you can bring back LIKE.
Swap the aggregation:
SELECT
(CASE WHEN disease LIKE '%Anemia%' THEN 'Anemia'
WHEN disease like '%Injuries%' THEN 'Injury'
END) AS disease,
SUM (p.gender = 'Female') AS females,
SUM (p.gender = 'Male') AS males
FROM phc_db.record r
INNER JOIN phc_db.patient p
ON r.malteser_id = p.malteser_id
WHERE disease REGEXP 'Anemia|Injuries'
GROUP BY disease;
You can do in c# with following query which will get all the diseases
SELECT p.gender, disease
FROM phc_db.record r, phc_db.patient p
where r.malteser_id=p.malteser_id
The use following c#
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("Gender", typeof(string));
dt.Columns.Add("Disease", typeof(string));
dt.Rows.Add(new object[] { "Male", "Anemia"});
dt.Rows.Add(new object[] { "Female", "Anemia"});
dt.Rows.Add(new object[] { "Male", "Anemia"});
dt.Rows.Add(new object[] { "Female", "Anemia"});
dt.Rows.Add(new object[] { "Male", "Anemia"});
dt.Rows.Add(new object[] { "Male","Injuries" });
dt.Rows.Add(new object[] { "Female", "Injuries" });
dt.Rows.Add(new object[] { "Male", "Injuries" });
dt.Rows.Add(new object[] { "Female", "Injuries" });
string[] uniqueDieses = dt.AsEnumerable().Select(x => x.Field<string>("Disease")).Distinct().ToArray();
DataTable pivot = new DataTable();
pivot.Columns.Add("Disease", typeof(string));
pivot.Columns.Add("Male", typeof(int));
pivot.Columns.Add("Female", typeof(int));
var groups = dt.AsEnumerable()
.GroupBy(x => x.Field<string>("Disease")).Select(x => new
{
disease = x.Key,
male = x.Where(y => y.Field<string>("Gender") == "Male").Count(),
female = x.Where(y => y.Field<string>("Gender") == "Female").Count()
}).ToList();
foreach (var group in groups)
{
pivot.Rows.Add(new object[] { group.disease, group.male, group.female });
}
}
}
}

Categories