One column GridView data to multiple chart series - c#

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");
}
}
}
}
}

Related

how to DataTable split into mutiple datatables 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);
}
}
}
}

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 });
}
}
}
}

How to Change DataRow value of one datatable to colum name of new Datatable?

My first DataTable is
Name | Value
---------------+----------
A | 12
B | 22
and i want this table as
A | B
---------------+----------
12 | 22
How to resolve this,please help me i tried a lot but i didn't get.Thank You in Advance.
You can convert rows into column using below line of code:
DataTable Pivot(DataTable table, string pivotColumnName)
{
// TODO make sure the table contains at least two columns
// get the data type of the first value column
var dataType = table.Columns[1].DataType;
// create a pivoted table, and add the first column
var pivotedTable = new DataTable();
pivotedTable.Columns.Add("Row Name", typeof(string));
// determine the names of the remaining columns of the pivoted table
var additionalColumnNames = table.AsEnumerable().Select(x => x[pivotColumnName].ToString());
// add the remaining columns to the pivoted table
foreach (var columnName in additionalColumnNames)
pivotedTable.Columns.Add(columnName, dataType);
// determine the row names for the pivoted table
var rowNames = table.Columns.Cast<DataColumn>().Select(x => x.ColumnName).Where(x => x != pivotColumnName);
// fill in the pivoted data
foreach (var rowName in rowNames)
{
// get the value data from the appropriate column of the input table
var pivotedData = table.AsEnumerable().Select(x => x[rowName]);
// make the rowName the first value
var data = new object[] { rowName }.Concat(pivotedData).ToArray();
// add the row
pivotedTable.Rows.Add(data);
}
return pivotedTable;
}
In case you have any problem or query please feel free to ask me.
Here is a pivot table
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication33
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(int));
dt.Columns.Add("Date", typeof(DateTime));
dt.Rows.Add(new object[] {"A", 100, DateTime.Parse("12/1/16")});
dt.Rows.Add(new object[] { "A", 101, DateTime.Parse("12/2/16") });
dt.Rows.Add(new object[] { "A", 102, DateTime.Parse("12/3/16") });
dt.Rows.Add(new object[] { "A", 103, DateTime.Parse("12/4/16") });
dt.Rows.Add(new object[] { "B", 104, DateTime.Parse("12/1/16") });
dt.Rows.Add(new object[] { "B", 110, DateTime.Parse("12/2/16") });
dt.Rows.Add(new object[] { "B", 114, DateTime.Parse("12/3/16") });
dt.Rows.Add(new object[] { "B", 112, DateTime.Parse("12/4/16") });
dt.Rows.Add(new object[] { "B", 100, DateTime.Parse("12/5/16") });
dt.Rows.Add(new object[] { "C", 120, DateTime.Parse("12/1/16") });
dt.Rows.Add(new object[] { "C", 130, DateTime.Parse("12/2/16") });
dt.Rows.Add(new object[] { "C", 140, DateTime.Parse("12/3/16") });
dt.Rows.Add(new object[] { "C", 150, DateTime.Parse("12/4/16") });
dt.Rows.Add(new object[] { "C", 160, DateTime.Parse("12/5/16") });
dt.Rows.Add(new object[] { "C", 101, DateTime.Parse("12/6/16") });
string[] uniqueNames = dt.AsEnumerable().Select(x => x.Field<string>("Name")).Distinct().ToArray();
var groups = dt.AsEnumerable().GroupBy(x => x.Field<DateTime>("Date")).ToList();
DataTable pivot = new DataTable();
pivot.Columns.Add("Date", typeof(DateTime));
foreach (var name in uniqueNames)
{
pivot.Columns.Add(name, typeof(string));
}
foreach (var group in groups)
{
DataRow newRow = pivot.Rows.Add();
newRow["Date"] = group.Key;
foreach (DataRow row in group)
{
newRow[row.Field<string>("Name")] = row.Field<int>("Value");
}
}
}
}
}

The best way to search in DataTable on multiple conditions in C#?

I have 2 DataTable with the following columns:
Table 1
Title
NUMBER
Sub_num1
Sub_num2
Table 2
NUMBER
Sub_num1
Sub_num2
In Table 2 Combination of NUMBER, Sub_num1 and Sub_num2 is unique. Can be Many NUMBERS, but with different set of Sub1 and Sub2.
In Table 1 Title is unique. A couple titles can have the same NUMBER, but again different set of Subs.
I need to loop through Table 2 and check if Table 1 has exact match with all 3 columns, then get this title, if not I need to get all Titles that have this NUMBER.
What is the best and fastest way to do this search? On the top of my head I have only next:
Loop through records in Table 2 and for each record loop through Table 1 and check for match, but I think that this process can be very resource-intensive...
Any help, please?
UPDATE
Example:
var dt1 = new DataTable("Table 1");
dt1.Columns.Add("title", typeof(string));
dt1.Columns.Add("number", typeof(int));
dt1.Columns.Add("subnum1", typeof(int));
dt1.Columns.Add("subnum2", typeof(int));
dt1.Rows.Add(new object[] { "a", 1111, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "b", 2222, 1, 1 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "b", 2222, 2, 2 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "d", 3333, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "d", 3333, 1, 2 });
dt1.Rows.Add(new object[] { "d", 3333, 2, 1 });
var dt2 = new DataTable("Table 2");
dt2.Columns.Add("number", typeof(int));
dt2.Columns.Add("subnum1", typeof(int));
dt2.Columns.Add("subnum2", typeof(int));
dt2.Rows.Add(new object[] { 1111, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 2222, "", 5 }); // Only NUMBER match
dt2.Rows.Add(new object[] { 3333, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 3333, "", "" }); // Only NUMBER match
SO I'm looping through Table 2:
foreach (DataRow row in dt2.Rows)
{
// HERE Should be logic and search
}
RESULT should be:
If match print title, if not print ALL titleS with number, that match, so:
1. "a", 1111, 1, 1
2.1 "b", 2222, 1, 1
2.2 "b", 2222, 2, 2
3. "d", 3333, 1, 1
4.1 "d", 3333, 1, 1
4.2 "d", 3333, 1, 2
4.3 "d", 3333, 2, 1
One possibility would be to use the DataTable class build in filtering. You can define a dynamic filter and apply it to the DataTable object. The dynamic filter language is something like a subset of SQL, it has LIKE and other SQL keywords. An example of filtering code:
var dt = new DataTable("test");
dt.Columns.Add("A", typeof(string));
dt.Columns.Add("B", typeof(string));
dt.Rows.Add(new object[] { "a", "1" });
dt.Rows.Add(new object[] { "a", "2" });
var rows = dt.Select("B = '2'");
This way you can define the filter and apply it to both tables and compare only the result set and not every entry. The result is an array of Rows.
I used it in a project, that has DataTable objects containing more than 2K entries each and the performance is really good.
Another possibility would be to use LINQ to filter the data. You can query the DataTable's rows like this:
var rows = (from DataRow dr in dt.Rows
where dr["B"] == "2"
select dr).ToList();
This query returns the same result as the direct filtering. You can apply again the same approach here to check the mathching result only.
If i understood your question correctly, a possible solution to your problem could look like this:
// test DataTable objects for the example
var dt1 = new DataTable("Table 1");
dt1.Columns.Add("title", typeof(string));
dt1.Columns.Add("number", typeof(int));
dt1.Columns.Add("subnum1", typeof(int));
dt1.Columns.Add("subnum2", typeof(int));
dt1.Rows.Add(new object[] { "a", 1111, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "b", 2222, 1, 1 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "b", 2222, 2, 2 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "d", 3333, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "d", 3333, 1, 2 });
dt1.Rows.Add(new object[] { "d", 3333, 2, 1 });
var dt2 = new DataTable("Table 2");
dt2.Columns.Add("number", typeof(int));
dt2.Columns.Add("subnum1", typeof(int));
dt2.Columns.Add("subnum2", typeof(int));
dt2.Rows.Add(new object[] { 1111, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 2222, 0, 5 }); // Only NUMBER match
dt2.Rows.Add(new object[] { 3333, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 3333, 0, 0 }); // Only NUMBER match
foreach (DataRow row in dt1.Rows)
{
var matches = dt2.Select(string.Format("number = {0} and subnum1 = {1} and subnum2 = {2}", row["number"], row["subnum1"], row["subnum2"]));
if (matches.Count() > 0)
{
Console.WriteLine(row["title"]);
}
else
{
var fallback = dt2.Select(string.Format("number = {0}", row["number"]));
if (fallback.Count() > 0)
{
Console.WriteLine(" > " + row["title"]);
}
}
}
The output in this case is:
a
> b
> b
d
> d
> d
What values shoule be written to the output is up to you - at the point where the match is found you have all that you need.

Categories