datatable sum column and concatenate rows using LINQ and group by on multiple columns - vb.net

I Have a datatable with following records
ID NAME VALUE CONTENT
1 AAA 10 SYS, LKE
2 BBB 20 NOM
1 AAA 15 BST
3 CCC 30 DSR
2 BBB 05 EFG
I want to write a VB.NET/LINQ query to have a output like below table: -
ID NAME SUM CONTENT (as CSV)
1 AAA 25 SYS, LKE, BST
2 BBB 25 NOM, EFG
3 CCC 30 DSR
Please provide me LINQ query to get the desired result. Thanks.
I have tried concatenation using below query
Dim grouped = From row In dtTgt.AsEnumerable() _
Group row By New With {row.Field(Of Int16)("ID"), row.Field(Of String)("Name")} _
Into grp() _
Select ID, Name, CONTENT= String.Join(",", From i In grp Select i.Field(Of String)("CONTENT"))

This query will give you the expected output:-
Dim result = From row In dt.AsEnumerable()
Group row By _group = New With {Key .Id = row.Field(Of Integer)("Id"),
Key .Name = row.Field(Of String)("Name")} Into g = Group
Select New With {Key .Id = _group.Id, Key .Name = _group.Name,
Key .Sum = g.Sum(Function(x) x.Field(Of Integer)("Value")),
Key .Content = String.Join(",", g.Select(Function(x) x.Field(Of String)("Content")))}

Thanks for your answers.
However, I have managed to get the desired result using simple code (Without LINQ): -
Dim dt2 As New DataTable
dt2 = dt.Clone()
For Each dRow As DataRow In dt.Rows
Dim iID As Integer = dRow("ID")
Dim sName As String = dRow("Name")
Dim sContt As String = dRow("Content")
Dim iValue As Integer = dRow("Value")
Dim rwTgt() As DataRow = dt2.Select("ID=" & iID)
If rwTgt.Length > 0 Then
rwTgt(0)("Value") += iValue
rwTgt(0)("Content") += ", " & sContt
Else
rw = dt2.NewRow()
rw("ID") = iID
rw("Name") = sName
rw("Value") = iValue
rw("Content") = sContt
dt2.Rows.Add(rw)
End If
Next

Related

Using Linq for select row from DataTableA where id not in DataTableB

I have two dataTables ,and i want select all rows from DataTable1 where id is not in DataTable2.below what i have tried :
Sql = "select *,N°Reçu as NumRecu from V_Sit_J_Vente,V_Bien where V_Sit_J_Vente.Code_bien=V_Bien.Code_bien and date_situation <= '" + dt2 + "' and date_situation >= '" + dt1 + "'"
Dim GlobalDataVente As DataTable = utilitaire.getDataSet(Sql).Tables(0)
Sql = "select * from V_Reserv_Annule"
Dim GlobalDataAnnule As DataTable = utilitaire.getDataSet(Sql).Tables(0)
Dim query = (From order In GlobalDataVente.AsEnumerable() _
Where order!code_projet = tab.Rows(i).Item("code_projet")).ToList
Dim bannedCCList = From c In GlobalDataAnnule.AsEnumerable() _
Where c!type.Equals("Transfert acompte") = False And c!date_annule <= dt2
Dim exceptBanned = From c In query Group Join b In bannedCCList On c.Field(Of String)("N°Reçu") Equals b.Field(Of String)("num_reserv_remplace")
Into j() From x In j.DefaultIfEmpty() Where x Is Nothing Select c
What i want that "exceptBanned " containt all rows of "query" except row exist in "bannedCCList "
Thanks in advance
You can use Contains for this:
Dim query = (From order In GlobalDataVente.AsEnumerable() _
Where order!code_projet = tab.Rows(i).Item("code_projet")).ToList
Dim bannedCCList = From c In GlobalDataAnnule.AsEnumerable() _
Where c.type.Equals("Transfert acompte") = False And c.date_annule <= dt2
Select c.Field(Of String)("num_reserv_remplace")
Dim exceptBanned = From c In query
Where Not bannedCCList.Contains(c.Field(Of String)("N°Reçu"))
Select c
bannedCCList defines a query that produces the Id values you want to exclude; exceptBanned combines query with this list of Ids into a query that only runs once to return the final results. It works this way because bannedCCList is an IEnumerable. It isn't executed when it's defined, only when it's actually used.

Cross table VB.NET & SQL Server & Linq

I have a table like this:
MAName feldtext
------------------
karl fieldtext1
karl fieldtext2
karl fieldtext1
karl fieldtext3
karl fieldtext4
karl fieldtext2
karl fieldtext5
karl fieldtext3
karl fieldtext3
susi fieldtext1
susi fieldtext4
john fieldtext2
john fieldtext5
john fieldtext5
and I need:
MAName fieldtext1 fieldtext2 fieldtext3 fieldtext4 fieldtext5 FehlerJeMA
karl 2 2 3 1 1 9
susi 1 0 0 1 0 2
john 0 1 0 0 2 3
The columns fieldtext can go from fieldtext1 to fieldtextn, it's dynamic, depending on query.
I was looking here for solutions and found, so my approach:
Dim dt2 As New DataTable
Dim nn As Integer = 0
Dim Zeile As DataRow
dt2.Columns.Add("MAName")
' fieldtext distinct
Dim query2 = (From dr In (From d In newTable2.AsEnumerable Select New With {.feldtext1 = d("feldtext")}) Select dr.feldtext1 Distinct)
For Each Feldtext In query2
dt2.Columns.Add(Feldtext)
Next
column = New DataColumn()
column.DataType = System.Type.GetType("System.Int32")
column.ColumnName = "FehlerJeMA"
dt2.Columns.Add(column)
' MAName distinct
Dim query3 = (From dr In (From d In newTable2.AsEnumerable Select New With {.MAName2 = d("MAName")}) Select dr.MAName2.ToString.ToLower Distinct)
For Each Mitarbeiter In query3
Zeile = dt2.NewRow()
Zeile(0) = Mitarbeiter.ToString.ToLower
MA2 = Mitarbeiter.ToString.ToLower
nn = 1
For Each colName2 In query2
Fehler2 = colName2
Dim AnzahlFehler As String = (From row In newTable2.Rows Select row Where row("MAName").ToString.ToLower = MA2 And row("feldtext") = Fehler2).Count
If AnzahlFehler = 0 Then
AnzahlFehler = ""
End If
Zeile(nn) = AnzahlFehler
nn += 1
If AnzahlFehler <> "" Then
FehlerJeMA += CInt(AnzahlFehler)
End If
Next
Zeile(nn) = FehlerJeMA
dt2.Rows.Add(Zeile)
Next
This works, but is very slow...
It could be the case that in my table has more than 10.000 rows...
So my question is: what is fastest approach to get the result?
Is it some kind of cross table with linq? Other approaches?
In C# you will be able to use the code, try to translate it for your problem:
var pivotData = data.GroupBy(x => new {x.MAName, x.feldtext}, (key, group) => new { MAName = key.Column1, feldtext = key.Column2, count = group.Count() });

Display only certain rows in datatable

So I have a dataset like below
Col1 Col2 Col3 Col4
Apple 1 10 Orange
Apple 2 20 Orange
Apple 3 30 Orange
Apple 1 10 Pear
Apple 2 20 Pear
Apple 3 30 Pear
Orange 1 10 grapes
Orange 2 20 grapes
ORange 1 10 kiwi
Berries 1 10 apple
Berries 1 20 Kiwi
I just need something like
Col1 Col2 Col3 Col4
Apple 1 10 Orange
Apple 2 20 Orange
Apple 3 30 Orange
ORange 1 10 Grapes
Orange 2 20 Grapes
Berries 1 10 Apple
So basically it is the col1 and col4, if col4 changes for col1 as I read through the rows, I should'nt display that
Could someone please help me
After first's suggestion
For i As Integer = 0 To dtResults.Rows.Count - 1
Dim firstItem As String = dtResults.Rows(i)("col1").ToString()
Dim firstToB As String = dtResults.Rows(i)("col4").ToString()
dtResults.DefaultView.RowFilter = "col4= '" + firstToB + "'"
Dim tempTable As DataTable = dtResults.DefaultView.ToTable()
Dim Total As Integer = 0
For Each dr As DataRow In tempTable.Rows
'Dim firstItem As String = dr("col1").ToString()
'If (dr("col1") = firstItem) AndAlso (firstToBin = dr("col4")) Then
If item Is Nothing OrElse item <> dr("col1") Then
If Not item Is Nothing Then
dgv.Rows.Add()
End If
itemnum = dr("col1")
Else
itemnum = ""
desc = ""
size = ""
Total += dr("col3")
End If
item = dr("col1")
dgv.Rows.Add(dr('',dr('',dr('')...)
count += 1
'End If
Next
Next
You will need to filter through your DataTable's rows. You can use the DefaultView in order to do this.
For example:
Dim ds1 As New DataSet1 'Create an instance of your DataSet1
ds1.yourDataTable.DefaultView.RowFilter = "Col4='Orange'"
If your DataSet's DataTables are created in the Visual Studio's designer, you can specify the DataType (string, integer, boolean) for each column. By default the DataType is set to a string.
You can do this in two ways
Filtering and Sorting using DataViews
Filtering and Sorting using DataTables
So to achieve as mentioned in the question here is what I did. I can always make changes in Stored procedure but I should be able to see those rows also in dataset for some other purpose. And so to bind the Grid I took row's item like below loop through
For i As Integer = 0 To dtResults.Rows.Count - 1
Dim firstItem As String = dtResults.Rows(i)("col1").ToString()
If acceptitem Is Nothing OrElse acceptitem <> firstItem Then
Dim firstToB As String = dtResults.Rows(i)("col4").ToString()
dtResults.DefaultView.RowFilter = "col4 = '" + firstToB + "' AND col1 = '" + firstItem + "'"
Dim tempTable As DataTable = dtResults.DefaultView.ToTable()
Dim Total As Integer = 0 ' dtResults.Rows(i)("col3").ToString()
For Each dr As DataRow In tempTable.Rows
acceptitem = dr("col1").ToString()
If item Is Nothing OrElse item <> dr("col1") Then
If Not item Is Nothing Then
dgv.Rows.Add()
End If
itemnum = dr("col1")
Total += Convert.ToInt16(dr("col3").ToString())
Else
itemnum = ""
Total += Convert.ToInt16(dr("col3").ToString())
End If
item = dr("col1")
dgv.Rows.Add(dr('',dr('',dr('').......)
count += 1
Next
End If
Next
Thanks so much for all the other suggestions...

How to remove only one row among duplicate rows in a datatable

I've a datatable dtPackageTest with following rows in it
testid testname
------ -----------
1 abc
2 xyz
1 abc
2 xyz
I followed this answer to but it removes all the duplicate rows, and my expected output is
testid testname
------ -----------
1 abc
2 xyz
My code:
Dim tblDups = From r In dtPackageTest _
Group By Dups = New With {Key .testid = CInt(r("testid")), Key .test = CStr(r("test"))} Into Group _
Where (Group.Count > 1) _
Select Dups
Dim dupRowList = (From r In dtPackageTest _
Join dupRow In tblDups _
On dupRow.testid Equals CInt(r("testid")) _
And dupRow.test Equals CStr(r("test")) _
Select r).ToList()
For Each dup In dupRowList
dtPackageTest.Rows.Remove(dup)
Next
Make following changes in your existing code,this will work as you expected :
(I guess this should be an old school logic but it works )
'Add order by - Order By Dups.testid
Dim tblDups = From r In dtPackageTest _
Group By Dups = New With {Key .testid = CInt(r("testid")), Key .test = CStr(r("test"))} Into Group _
Where (Group.Count > 1) Order By Dups.testid _
Select Dups
'Add order by - Order By r("testid")
Dim dupRowList = (From r In dtPackageTest _
Join dupRow In tblDups _
On dupRow.testid Equals CInt(r("testid")) _
And dupRow.test Equals CStr(r("test")) Order By r("testid") _
Select r).ToList()
Dim id As Integer = 0
For Each dup In dupRowList
'Checking for testid is already removed or not
If id <> dup("testid") Then
id = dup("testid")
dtPackageTest.Rows.Remove(dup)
End If
Next

How to remove all duplicates in a data table in vb.net?

Consider my data table
ID Name
1 AAA
2 BBB
3 CCC
1 AAA
4 DDD
Final Output is
2 BBB
3 CCC
4 DDD
How can i remove the rows in the data table using Vb.Net
Any help is appreciated.
Following works if you only want the distinct rows(skip those with same ID and Name):
Dim distinctRows = From r In tbl
Group By Distinct = New With {Key .ID = CInt(r("ID")), Key .Name = CStr(r("Name"))} Into Group
Where Group.Count = 1
Select Distinct
' Create a new DataTable containing only the unique rows '
Dim tblDistinct = (From r In tbl
Join distinctRow In tblDistinct
On distinctRow.ID Equals CInt(r("ID")) _
And distinctRow.Name Equals CStr(r("Name"))
Select r).CopyToDataTable
If you want to remove the dups from the original table:
Dim tblDups = From r In tbl
Group By Dups = New With {Key .ID = CInt(r("ID")), Key .Name = CStr(r("Name"))} Into Group
Where Group.Count > 1
Select Dups
Dim dupRowList = (From r In tbl
Join dupRow In tblDups
On dupRow.ID Equals CInt(r("ID")) _
And dupRow.Name Equals CStr(r("Name"))
Select r).ToList()
For Each dup In dupRowList
tbl.Rows.Remove(dup)
Next
Here is your sample-data:
Dim tbl As New DataTable
tbl.Columns.Add(New DataColumn("ID", GetType(Int32)))
tbl.Columns.Add(New DataColumn("Name", GetType(String)))
Dim row = tbl.NewRow
row("ID") = 1
row("Name") = "AAA"
tbl.Rows.Add(row)
row = tbl.NewRow
row("ID") = 2
row("Name") = "BBB"
tbl.Rows.Add(row)
row = tbl.NewRow
row("ID") = 3
row("Name") = "CCC"
tbl.Rows.Add(row)
row = tbl.NewRow
row("ID") = 1
row("Name") = "AAA"
tbl.Rows.Add(row)
row = tbl.NewRow
row("ID") = 4
row("Name") = "DDD"
tbl.Rows.Add(row)
You can use the DefaultView.ToTable method of a DataTable to do the filtering like this:
Public Sub RemoveDuplicateRows(ByRef rDataTable As DataTable)
Dim pNewDataTable As DataTable
Dim pCurrentRowCopy As DataRow
Dim pColumnList As New List(Of String)
Dim pColumn As DataColumn
'Build column list
For Each pColumn In rDataTable.Columns
pColumnList.Add(pColumn.ColumnName)
Next
'Filter by all columns
pNewDataTable = rDataTable.DefaultView.ToTable(True, pColumnList.ToArray)
rDataTable = rDataTable.Clone
'Import rows into original table structure
For Each pCurrentRowCopy In pNewDataTable.Rows
rDataTable.ImportRow(pCurrentRowCopy)
Next
End Sub
Assuming you want to check all the columns, this should remove the duplicates from the DataTable (DT):
DT = DT.DefaultView.ToTable(True, Array.ConvertAll((From v In DT.Columns Select v.ColumnName).ToArray(), Function(x) x.ToString()))
Unless I overlooked it, this doesn't seem to be in the documentation (DataView.ToTable Method), but this also appears to do the same thing:
DT = DT.DefaultView.ToTable(True)