Datatable group and pivot - c#

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

Related

How can I create a DataGridView displaying tables in restaurant

Hello, I am codding a restaurant automation to improve myself.
I have a table called tables in the database.
I can fetch data as shown in the left datagridview. but I
could not split into columns like on the right datagridview
I hope I can explain.
private void FrmAnaEkran_Load(object sender, EventArgs e)
{
VerileriGetir();
}
private void VerileriGetir()
{
Veritabani vt = new Veritabani();
vt.ConnectionOpen();
vt.SqlQuery("select * from masalar");
DataTable dt = vt.GetDataTable();
vt.ConnectionClose();
List<masa> masalar = new List<masa>();
foreach (DataRow dr in dt.Rows)
{
masa m = new masa();
m.adi = dr[1].ToString();
masa.ID = Convert.ToInt32(dr[0]);
masalar.Add(m);
}
for (int i = 0; i < masalar.Count; i++)
{
int n = dataGridView1.Rows.Add();
dataGridView1.Rows[n].Cells[0].Value = masalar[i].adi;
}
}
Use GroupBy :
DataTable dt = new DataTable();
dt.Columns.Add("Masa", typeof(string));
dt.Rows.Add(new object[] { "Masa_1" });
dt.Rows.Add(new object[] { "Masa_2" });
dt.Rows.Add(new object[] { "Masa_3" });
dt.Rows.Add(new object[] { "Masa_4" });
dt.Rows.Add(new object[] { "Masa_5" });
dt.Rows.Add(new object[] { "Masa_6" });
dt.Rows.Add(new object[] { "Masa_7" });
dt.Rows.Add(new object[] { "Masa_8" });
dt.Rows.Add(new object[] { "Masa_9" });
dt.Rows.Add(new object[] { "Masa_10" });
dt.Rows.Add(new object[] { "Masa_11" });
dt.Rows.Add(new object[] { "Masa_12" });
dt.Rows.Add(new object[] { "Masa_13" });
var groups = dt.AsEnumerable().Select((x, i) => new {masa = x.Field<string>("Masa"), index = i}).GroupBy(x => x.index / 4);
DataTable dt2 = new DataTable();
dt2.Columns.Add("Column1", typeof(string));
dt2.Columns.Add("Column2", typeof(string));
dt2.Columns.Add("Column3", typeof(string));
dt2.Columns.Add("Column4", typeof(string));
foreach(var group in groups)
{
DataRow newRow = dt2.Rows.Add();
int col = 0;
foreach(var row in group)
{
newRow[col++] = row.masa;
}
}

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 change DataTable Rows to Columns in C#

How to Change dataTable Rows to Columns
DataTable dt=new DataTable();
dt = getData(); //Pull data from source file
I have below format rows in a dataTable.
Now I want change ANC_TYPE rows into columns?
How i can convert into below format ?
You want a pivot table :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication49
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("OPR_DT", typeof(DateTime));
dt.Columns.Add("OPR_HR", typeof(int));
dt.Columns.Add("ANC_TYPE", typeof(string));
dt.Columns.Add("ANC_REGION", typeof(string));
dt.Columns.Add("MARKET_RUN_ID", typeof(string));
dt.Columns.Add("XML_DATE_ITEM", typeof(string));
dt.Columns.Add("MW", typeof(decimal));
dt.Columns.Add("GROUP", typeof(int));
dt.Rows.Add(new object[] { DateTime.Parse("2/23/2017"), 1, "NR", "AS_CAISO_EXP", "DAM", "NS_CLR_PRC", 0.09, 1});
dt.Rows.Add(new object[] { DateTime.Parse("2/23/2017"), 1, "RD", "AS_CAISO_EXP", "DAM", "RD_CLR_PRC", 2.83, 2 });
dt.Rows.Add(new object[] { DateTime.Parse("2/23/2017"), 2, "NR", "AS_CAISO_EXP", "DAM", "NS_CLR_PRC", 0.01, 3 });
dt.Rows.Add(new object[] { DateTime.Parse("2/23/2017"), 2, "RD", "AS_CAISO_EXP", "DAM", "RD_CLR_PRC", 0.1, 4 });
string[] uniqueAncType = dt.AsEnumerable().Select(x => x.Field<string>("ANC_TYPE")).Distinct().ToArray();
DataTable pivot = new DataTable();
pivot.Columns.Add("OPR_DT", typeof(DateTime));
pivot.Columns.Add("OPR_HR", typeof(int));
pivot.Columns.Add("ANC_REGION", typeof(string));
pivot.Columns.Add("MARKET_RUN_ID", typeof(string));
foreach (string col in uniqueAncType)
{
pivot.Columns.Add(col, typeof(string));
}
var groups = dt.AsEnumerable()
.GroupBy(x => new {
opr_dt = x.Field<DateTime>("OPR_DT"),
opr_hr = x.Field<int>("OPR_HR"),
anc_region = x.Field<string>("ANC_REGION"),
run_id = x.Field<string>("MARKET_RUN_ID")
}).ToList();
foreach (var group in groups)
{
DataRow newRow = pivot.Rows.Add();
newRow["OPR_DT"] = group.Key.opr_dt;
newRow["OPR_HR"] = group.Key.opr_hr;
newRow["ANC_REGION"] = group.Key.anc_region;
newRow["MARKET_RUN_ID"] = group.Key.run_id;
foreach (DataRow ancType in group)
{
newRow[ancType.Field<string>("ANC_TYPE")] = ancType.Field<decimal>("MW");
}
}
}
}
}

compare and merge the datatable in C# [duplicate]

Let T1 and T2 are DataTables with following fields
T1(CustID, ColX, ColY)
T2(CustID, ColZ)
I need the joint table
TJ (CustID, ColX, ColY, ColZ)
How this can be done in C# code in a simple way? Thanks.
If you are allowed to use LINQ, take a look at the following example. It creates two DataTables with integer columns, fills them with some records, join them using LINQ query and outputs them to Console.
DataTable dt1 = new DataTable();
dt1.Columns.Add("CustID", typeof(int));
dt1.Columns.Add("ColX", typeof(int));
dt1.Columns.Add("ColY", typeof(int));
DataTable dt2 = new DataTable();
dt2.Columns.Add("CustID", typeof(int));
dt2.Columns.Add("ColZ", typeof(int));
for (int i = 1; i <= 5; i++)
{
DataRow row = dt1.NewRow();
row["CustID"] = i;
row["ColX"] = 10 + i;
row["ColY"] = 20 + i;
dt1.Rows.Add(row);
row = dt2.NewRow();
row["CustID"] = i;
row["ColZ"] = 30 + i;
dt2.Rows.Add(row);
}
var results = from table1 in dt1.AsEnumerable()
join table2 in dt2.AsEnumerable() on (int)table1["CustID"] equals (int)table2["CustID"]
select new
{
CustID = (int)table1["CustID"],
ColX = (int)table1["ColX"],
ColY = (int)table1["ColY"],
ColZ = (int)table2["ColZ"]
};
foreach (var item in results)
{
Console.WriteLine(String.Format("ID = {0}, ColX = {1}, ColY = {2}, ColZ = {3}", item.CustID, item.ColX, item.ColY, item.ColZ));
}
Console.ReadLine();
// Output:
// ID = 1, ColX = 11, ColY = 21, ColZ = 31
// ID = 2, ColX = 12, ColY = 22, ColZ = 32
// ID = 3, ColX = 13, ColY = 23, ColZ = 33
// ID = 4, ColX = 14, ColY = 24, ColZ = 34
// ID = 5, ColX = 15, ColY = 25, ColZ = 35
I wanted a function that would join tables without requiring you to define the columns using an anonymous type selector, but had a hard time finding any. I ended up having to make my own. Hopefully this will help anyone in the future who searches for this:
private DataTable JoinDataTables(DataTable t1, DataTable t2, params Func<DataRow, DataRow, bool>[] joinOn)
{
DataTable result = new DataTable();
foreach (DataColumn col in t1.Columns)
{
if (result.Columns[col.ColumnName] == null)
result.Columns.Add(col.ColumnName, col.DataType);
}
foreach (DataColumn col in t2.Columns)
{
if (result.Columns[col.ColumnName] == null)
result.Columns.Add(col.ColumnName, col.DataType);
}
foreach (DataRow row1 in t1.Rows)
{
var joinRows = t2.AsEnumerable().Where(row2 =>
{
foreach (var parameter in joinOn)
{
if (!parameter(row1, row2)) return false;
}
return true;
});
foreach (DataRow fromRow in joinRows)
{
DataRow insertRow = result.NewRow();
foreach (DataColumn col1 in t1.Columns)
{
insertRow[col1.ColumnName] = row1[col1.ColumnName];
}
foreach (DataColumn col2 in t2.Columns)
{
insertRow[col2.ColumnName] = fromRow[col2.ColumnName];
}
result.Rows.Add(insertRow);
}
}
return result;
}
An example of how you might use this:
var test = JoinDataTables(transactionInfo, transactionItems,
(row1, row2) =>
row1.Field<int>("TransactionID") == row2.Field<int>("TransactionID"));
One caveat: This is certainly not optimized, so be mindful when getting to row counts above 20k. If you know that one table will be larger than the other, try to put the smaller one first and the larger one second.
This is my code. Not perfect, but working good. I hope it helps somebody:
static System.Data.DataTable DtTbl (System.Data.DataTable[] dtToJoin)
{
System.Data.DataTable dtJoined = new System.Data.DataTable();
foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
dtJoined.Columns.Add(dc.ColumnName);
foreach (System.Data.DataTable dt in dtToJoin)
foreach (System.Data.DataRow dr1 in dt.Rows)
{
System.Data.DataRow dr = dtJoined.NewRow();
foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
dr[dc.ColumnName] = dr1[dc.ColumnName];
dtJoined.Rows.Add(dr);
}
return dtJoined;
}
this function will join 2 tables with a known join field, but this cannot allow 2 fields with the same name on both tables except the join field, a simple modification would be to save a dictionary with a counter and just add number to the same name filds.
public static DataTable JoinDataTable(DataTable dataTable1, DataTable dataTable2, string joinField)
{
var dt = new DataTable();
var joinTable = from t1 in dataTable1.AsEnumerable()
join t2 in dataTable2.AsEnumerable()
on t1[joinField] equals t2[joinField]
select new { t1, t2 };
foreach (DataColumn col in dataTable1.Columns)
dt.Columns.Add(col.ColumnName, typeof(string));
dt.Columns.Remove(joinField);
foreach (DataColumn col in dataTable2.Columns)
dt.Columns.Add(col.ColumnName, typeof(string));
foreach (var row in joinTable)
{
var newRow = dt.NewRow();
newRow.ItemArray = row.t1.ItemArray.Union(row.t2.ItemArray).ToArray();
dt.Rows.Add(newRow);
}
return dt;
}
I tried to do this in next way
public static DataTable JoinTwoTables(DataTable innerTable, DataTable outerTable)
{
DataTable resultTable = new DataTable();
var innerTableColumns = new List<string>();
foreach (DataColumn column in innerTable.Columns)
{
innerTableColumns.Add(column.ColumnName);
resultTable.Columns.Add(column.ColumnName);
}
var outerTableColumns = new List<string>();
foreach (DataColumn column in outerTable.Columns)
{
if (!innerTableColumns.Contains(column.ColumnName))
{
outerTableColumns.Add(column.ColumnName);
resultTable.Columns.Add(column.ColumnName);
}
}
for (int i = 0; i < innerTable.Rows.Count; i++)
{
var row = resultTable.NewRow();
innerTableColumns.ForEach(x =>
{
row[x] = innerTable.Rows[i][x];
});
outerTableColumns.ForEach(x =>
{
row[x] = outerTable.Rows[i][x];
});
resultTable.Rows.Add(row);
}
return resultTable;
}
Note that if you have a DataSet, you will need to steal the table from the Dataset with dataSet.Table[0]

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

Categories

Resources