Rearrange DB query result in array for duplicate rows - c#

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.

Related

c# Left joining 2 DataTable

I have 2 DataTables with no primary keys on either table. I need all records in DataTable1 to be left joined with DataTable2. I've solved it a couple of ways but are they performant?
Column2 is the soft "key" and I am trying to populate the column 3 field in DataTable1 from DataTable2.
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
DataTable dt1 = new DataTable();
dt1.Columns.Add("col1", typeof(int));
dt1.Columns.Add("col2", typeof(string));
dt1.Columns.Add("col3", typeof(string));
dt1.Rows.Add(1, "One");
dt1.Rows.Add(1, "Two");
dt1.Rows.Add(3, "Two");
DataTable dt2 = new DataTable();
dt2.Columns.Add("col1", typeof(int));
dt2.Columns.Add("col2", typeof(string));
dt2.Columns.Add("col3", typeof(string));
dt2.Rows.Add(1, "One", "One Description");
dt2.Rows.Add(2, "Two", "Two Description");
//Solution 1
//foreach (DataRow row in dt1.Rows)
//{
// row[2] = dt2.Select("col2='" + row[1] + "'")[0]["col3"];
//}
foreach (DataRow row in dt1.Rows)
{
row[2] = dt2.AsEnumerable().Where(x => x["col2"] == row[1]).FirstOrDefault()[2];
}
dt1.AsEnumerable().ToList().ForEach(x =>
Console.WriteLine(
"col1:{0} col2:{1} col3:{2}"
, x[0], x[1], x[2])
);
}
}
}
Bonus: I tried to copy this into .Net Fiddle but it doesn't seem to like the AsEnumerable on the DataTable. Go .Net Fiddle
You can use LINQ GroupJoin for that:
var result = dt1.Select()
.GroupJoin(dt2.Select(), t1 => t1[1], t2 => t2[1], (t1, t2) => { t1[2] = t2.FirstOrDefault()?[2]; return t1; })
.ToList();

update one datatable from another after comparing primary key of both

I have two datatables and each has different 70-80 columns. I want to update the values of one datatable field with other datatable field values which are matching after comparing the primary keys of both in c#.
suppose I have one data table dt1 contains rows and 60 columns.
I have another datatable dt2 contains rows and 70 columns.
and 10 columns of dt1 matches with dt2. 30 rows of dt1 matches with dt2.
so I want to compare the primary key of both datatable and after if they match the update column values from dt1 to dt2.
Here is your answer, consider dt1=Customer and dt2=Order, CustomerId exist in both datatables, and i also joined them using LINQ extension method, and finally select columns from both datatables. Thanks.
static void Main(string[] args)
{
DataTable dt1 = new DataTable(); //dt1=Customer
dt1.Columns.Add("CustomerId", typeof(int));
dt1.Columns.Add("Name", typeof(string));
dt1.Rows.Add(1, "Customer A");
dt1.Rows.Add(2, "Customer B");
dt1.Rows.Add(3, "Customer C");
DataTable dt2 = new DataTable(); //dt2=Order
dt2.Columns.Add("OrderId", typeof(int));
dt2.Columns.Add("CustomerId", typeof(int)); //Fk
dt2.Columns.Add("OrderDate", typeof(DateTime));
dt2.Columns.Add("OrderAmount", typeof(double));
dt2.Rows.Add(1, 1,DateTime.Now,15000);
dt2.Rows.Add(2, 1, DateTime.Now,10000);
dt2.Rows.Add(3, 2, DateTime.Now,25000);
var result = dt2.AsEnumerable()
.Join(dt1.AsEnumerable(),
x => x.Field<int>("CustomerId"), //Order(CustomerId) FK
y => y.Field<int>("CustomerId"), //Customer Id(Pk)
(x, y) => new { dt2 = x, dt1 = y }) //dt2=Order, dt1=Customer
.Select(x => new
{
OrderId = x.dt2.Field<int>("OrderId"),
CustomerId = x.dt1.Field<int>("CustomerId"),
Name = x.dt1.Field<string>("Name"),
OrderDate = x.dt2.Field<DateTime>("OrderDate"),
OrderAmount = x.dt2.Field<double>("OrderAmount"),
});
foreach (var item in result)
{
Console.WriteLine("Order Id: {0}, CustomerId: {1}, Name: {2}, OrderDate: {3}, OrderAmount: {4}",
item.OrderId,item.CustomerId,item.Name,item.OrderDate,item.OrderAmount);
}
Console.ReadKey();
}
You will need to reference the tables individually unfortunately.
UPDATE tbl1 SET
col2c=(SELECT colc2 FROM tbl2 WHERE tbl2_pk=tbl1.tbl1_pk),
col4e=(SELECT cole4 FROM tbl2 WHERE tbl2_pk=tbl1.tbl1_pk)
WHERE test.tbl1.tbl1_pk=(SELECT tbl2_pk FROM tbl2 WHERE tbl1_pk=tbl2_pk)
Link to see results in table pre and post execution

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

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

Get distinct values from a datatable

I have a DataTable with values:
ID NameID Name
1 1 qwe
2 2 ert
3 2 ert
4 3 dffg
5 3 dffg
I want to get a DataTable containing distinct rows like this:
ID NameID Name
1 1 qwe
2 2 ert
4 3 dffg
How can this be achieved using LINQ or other?
var rows = tbl.AsEnumerable().Select(row => row).ToList();
tbl = new DataTable();
tbl.Columns.Add("ID", typeof(Int32));
tbl.Columns.Add("NameID", typeof(Int32));
tbl.Columns.Add("Name", typeof(String));
rows.GroupBy(r => r.Field<int>("NameID"))
.Select(rr => rows.First(rw => rw.Field<Int32>("NameID") == rr.Key))
.ToList()
.ForEach(rname => tbl.Rows.Add(new object []
{
rname.Field<Int32>("ID"),
rname.Field<Int32>("NameID"),
rname.Field<String>("Name"),
}));
Test data setup:
DataTable tbl = new DataTable();
tbl.Columns.Add("ID", typeof (Int32));
tbl.Columns.Add("NameID", typeof (Int32));
tbl.Columns.Add("Name", typeof (String));
tbl.Rows.Add(new object[] { 1, 1, "qwe" });
tbl.Rows.Add(new object[] { 2, 2, "ert" });
tbl.Rows.Add(new object[] { 3, 2, "ert" });
tbl.Rows.Add(new object[] { 4, 3, "dffg" });
tbl.Rows.Add(new object[] { 5, 3, "dffg" });
Assign the datatable to a dataview and with the dataview object we can use RowFilter as follows.
Dim DTb As New DataTable()
DataView dView= new DataView(DTb);
dView.RowFilter = strCondition.ToString //strCondition contains the condition to filter
The strCondition will contain the Conditions to filter, and after filtering reassign the dataview to the datatable as follows
DTb = dView.ToTable()
Try,
var result = from ele in dt.AsEnumerable()
group ele by ele["NameID"] into g
select g.FirstOrDefault();
foreach (var t in result)
Console.WriteLine(t[0] + " " + t[1] + " " + t[2]);

Categories

Resources