Finding Duplicate rows in datatable in VB.net - vb.net

I have a datatable in VB.net with few columns - Number, Name , Salary.
I want to get a list/table of "Number" that has the same ID and Salary Reapeted more than once.
for example:
Number: 1 , Name: Dan, Salary: 2000
Number: 2 , Name: Robert, Salary: 300
Number: 1 , Name: Shone, Salary: 2000
Number: 3 , Name: Kelvin, Salary: 2000
Number: 3 , Name: Arnon, Salary: 5000
For this table I will get back "1". because it has duplicate 1 with a salary of 2000.
Thanks for anyone help

I created the DataTable, then used Linq to group it by Number and salary. The Where clause only chooses groups with count greater than 1. The Select collects the Number field.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim dt As New DataTable
dt.Columns.Add("Number", GetType(Long))
dt.Columns.Add("Name", GetType(String))
dt.Columns.Add("Salary", GetType(Long))
dt.Rows.Add(1, "Dan", 2000)
dt.Rows.Add(2, "Robert", 300)
dt.Rows.Add(1, "Shone", 2000)
dt.Rows.Add(3, "Kelvin", 2000)
dt.Rows.Add(3, "Arnon", 5000)
Dim result = From row In dt
Group row By NumberSalary = New With {
Key .Number = row.Field(Of Long)("Number"),
Key .Salary = row.Field(Of Long)("Salary")}
Into Group
Where Group.Count > 1
Select New With {
Key .Number = NumberSalary.Number}
For Each r In result
Debug.Print(r.ToString) 'Prints { Number = 1 } in the Immediate window
Next
End Sub

Related

How to do Loop to calculate the cell values in DataGridView?

How to multiply a value of a row of a column to all the values in another column and do the loop for all rows.Then, at the end, sum the values in each row?
Here is an example.
Please note that I do not need to have or show these three columns (I, II, III). I just put them in there to show the steps.
Thanks a lot for your help!
The loop works only for the 1st two rows in Column 3..!!?
Dim i As Integer
For k As Integer = 0 To Data1.ColumnCount - 4
For j = 0 to Data1.Rows.Count - 2
Data1.Rows(j).Cells(2).Value = Data1.Rows(j).Cells(0).Value * _
Data1.Rows(j).Cells(1).Value
For i = 0 To EOF()
i = i + 1
Data1.Rows(j).Cells(3).Value = Data1.Rows(j).Cells(0).Value *_
Data1.Rows(k+i).Cells(1).Value + Data1.Rows(j).Cells(2).Value
Next i
Next j
Next k
This solution doesn't use a DataGridView (or GridView) but using arrays. The trick is creating a list of row, column and the multiplication result. See the table below to see how the list looks like. After the list is built, it's just grouping by the second value (row) and calculate the sum the third value.
Dim C1 = { 40, 30, 20, 10 } ' column C1
Dim C2 = { 1, 2, 3 } ' column C2
' to store the result of multiplication between C1 and C2
' first value is Column, second value is Row, third column is the multiplication result
Dim list = New List(Of Tuple(Of Integer, Integer, Integer))
For i = 0 To C2.Length - 1
For j = 0 To C1.Length - 1
list.Add(New Tuple(Of Integer, Integer, Integer)( i, i + j, C2(i) * C1(j) )) ' column, row, value
Next
Next
' to store sum of each row
' key is row, value is sum of the row
Dim dict = New Dictionary(Of Integer, Integer)
For Each row In list ' iterate each row in list
If dict.ContainsKey(row.Item2) ' if dictionary contains row number
dict(row.Item2) += row.Item3 ' add value to existing row
Else
dict.Add(row.Item2, row.Item3) ' add new row
End If
Next
For Each entry In dict
Console.WriteLine("Total Row {0} = {1}", entry.Key, entry.Value)
Next
Alternative using LINQ to get the sum.
Dim C1 = { 40, 30, 20, 10 } ' column C1
Dim C2 = { 1, 2, 3 } ' column C2
' to store the result of multiplication between C1 and C2
' first value is Column, second value is Row, third column is the multiplication result
Dim list = New List(Of Tuple(Of Integer, Integer, Integer))
For i = 0 To C2.Length - 1
For j = 0 To C1.Length - 1
list.Add(New Tuple(Of Integer, Integer, Integer)( i, i + j, C2(i) * C1(j) )) ' column, row, value
Next
Next
' LINQ sum
Dim result = From l In list
Group By l.Item2 ' group by row
Into Sum(l.Item3) ' sum of value
For Each row In result
Console.WriteLine("Total Row {0} = {1}", row.Item2, row.Sum)
Next
Spreadsheet version of the list with colored rows grouped by Row (2nd) column.
Result:
Total Row 0 = 40
Total Row 1 = 110
Total Row 2 = 200
Total Row 3 = 140
Total Row 4 = 80
Total Row 5 = 30
I hope you get the idea to implement this code in your project.
EDIT. Optimized solution with less looping.
Dim C1 = { 40, 30, 20, 10 } ' column C1
Dim C2 = { 1, 2, 3 } ' column C2
Dim dict = New Dictionary(Of Integer, Integer)
For i = 0 To C2.Length - 1
For j = 0 To C1.Length - 1
If dict.ContainsKey(i + j) ' if dictionary contains row number
dict(i + j) += C2(i) * C1(j) ' add value to existing row
Else
dict.Add(i + j, C2(i) * C1(j)) ' add new row
End If
Next
Next
For Each entry In dict
Console.WriteLine("Total Row {0} = {1}", entry.Key, entry.Value)
Next
Sample in Windows Form application. Add a DataGridView and a Button into the form.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadInitialData()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Calculate()
End Sub
Sub LoadInitialData()
DataGridView1.Rows.Clear()
DataGridView1.Rows.Add(40, 1)
DataGridView1.Rows.Add(30, 2)
DataGridView1.Rows.Add(20, 3)
DataGridView1.Rows.Add(10, Nothing)
End Sub
Sub Calculate()
Dim dict = New Dictionary(Of Integer, Integer)
For i = 0 To DataGridView1.Rows.Count - 1
For j = 0 To DataGridView1.Rows.Count - 1
' check if both are numbers
If IsNumeric(DataGridView1(0, i).Value) And IsNumeric(DataGridView1(1, j).Value) Then
Dim C1 = Convert.ToInt32(DataGridView1(0, i).Value) ' value of C1 from 1st column of outer loop
Dim C2 = Convert.ToInt32(DataGridView1(1, j).Value) ' value of C2 from 2nd column of inner loop
If dict.ContainsKey(i + j) Then ' check if dictionary has entry
dict(i + j) += C1 * C2 ' increment the value in dictionary
Else
dict.Add(i + j, C1 * C2) ' add new entry into dictionary
End If
End If
Next
Next
For Each entry In dict
' check if row in datagridview is lesser than dictionary entries
If DataGridView1.Rows.Count < dict.Keys.Count Then
DataGridView1.Rows.Add() ' add empty row
End If
DataGridView1(2, entry.Key).Value = entry.Value ' set value in 3rd column
Next
End Sub
End Class

Display number of rows and columns

I have in my table MS Access named ( Table1 ) two fields ( ID1 - Team1 ).
With NumericUpDown1 i select the number of rows that i want to display after randomize in DataGridView2.With NumericUpDown2 i select the number of columns that i want to display after randomize in DataGridView2.If i choose with NumericUpDown2 only one column ( the number 1 ) it work very well with this query :
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Con_randomize()
Dim rows As Integer
If Not Integer.TryParse(NumericUpDown1.Value, rows) Then
MsgBox("NUMBER NOT AVAILABLE", MsgBoxStyle.Critical + MsgBoxStyle.OkOnly, "Error")
NumericUpDown1.Value = ""
NumericUpDown1.Focus()
Exit Sub
End If
If NumericUpDown2.Value = 1 Then
Dim sql As String = String.Format("SELECT Top {0} ID1,Team1 From Table1 ORDER BY RND(-(100000*ID1)*Time())", rows)
InfoCommand = New OleDbCommand(sql, Con_randomize)
InfoAdapter = New OleDbDataAdapter()
InfoAdapter.SelectCommand = InfoCommand
InfoTable = New DataTable()
InfoAdapter.Fill(InfoTable)
DataGridView2.DataSource = InfoTable
DataGridView2.Columns(0).HeaderText = "NUMERO"
DataGridView2.Columns(1).HeaderText = "CATEGORY1"
End If
End Sub
How to make if i choose with NumericUpDown2 the number 2 or 3 columns i want to display in Datagridview2.
The columns will be named ( CATEGORY2 - CATEGORY3 ) . for example ( 1 Victor - David - Vincent ) ( 2 wiliam- George - Joseph ) ..in my only field named Team1 I have a hundred of the names
I'm not 100% sure why you need a query to initialize the data, but give this a go. It will automatically create the columns the way you need them.
' If NumericUpDown2.Value = 1 Then ' Comment This If Block Out
' Create the Teams String
Dim teamsString as New System.Text.StringBuilder("")
For i as Integer = 1 to Convert.ToInt32(NumericUpDown2.Value)
teamsString.Append(", (SELECT Top 1 Team1 From Table1 ORDER BY RND(-(100000*ID1)*Time())) as Category" + i.ToString())
Next
Dim sql As String = String.Format("SELECT Top {0} ID1" + teamsString.ToString() + " From Table1 ORDER BY RND(-(100000*ID1)*Time())", rows)
InfoCommand = New OleDbCommand(sql, Con_randomize)
InfoAdapter = New OleDbDataAdapter()
InfoAdapter.SelectCommand = InfoCommand
InfoTable = New DataTable()
InfoAdapter.Fill(InfoTable)
DataGridView2.DataSource = InfoTable
DataGridView2.Columns(0).HeaderText = "NUMERO"
' Don't Need This, We Made It the Binding Name
' DataGridView2.Columns(1).HeaderText = "CATEGORY1"

calculate rank from student marks stored in datatable in vb. net

I am working on examination result system in vb.net which requires to calculate student ranks based on marks obtained. Subject marks data is stored in database. I am loading the subject marks in a datatable
da.Fill(dt) 'added to a datagridview.
DataGridView1.DataSource = dt
then Add New columns in dt to show result:
dt.Columns.Add("Obtained Marks", GetType(String))
dt.Columns.Add("Percent", GetType(String))
dt.Columns.Add("Result", GetType(String))
dt.Columns.Add("Rank", GetType(Integer))
Then calculated total of all the subjects & added in obtained marks columns by looping through rows & columns of datatable.
For s As Integer = 0 To dt.Rows.Count - 1
For t As Integer = 0 To dt.Columns.Count - 1
obtmarks += CDbl(dt.Rows(s).Item(t))
Next
dt.Rows(s)("Obtained Marks") = obtmarks
dt.Rows(s)("Result") = "PASS"
dt.Rows(s)("Rank") = 'RANK OF STUDENT
Next
How can i calculate rank/position of students on the basis of total marks contained in datatable column "Obtained Marks".
i.e.
Student with marks 436 Rank should be 1
Student with marks 429.5 Rank should be 2
Student with marks 412 Rank should be 3 ....
so on until all the rows in record. (Image atttached)
if there is any function for datatable which can help here or how can i add the logic in the loop to calculate rank of students and add the value in rank column. Thanks
P.S. I dnt want to sort the rows on obtained marks, but want to Add rank of each student in front of his/her marks, which is already order by their Roll No.
You could use this code to set the Rank column in your table
DataView dv = new DataView(dt, "", "ObtainedMarks desc", DataViewRowState.CurrentRows);
for(int x = 0; x < dv.Count; x++)
dv[x].Row["Rank"] = x+1;
This could be done only after you have completed the code that calculates the column ObtainedMarks
Also, I suggest to execute all before setting the DataSource of the DataGridView to avoid unnecessary delays in the grid repainting itself when you have not yet finished with it
EDIT
To have the same rank for persons with the same marks you could try something like this
int lastMark = -1;
int currentRank = 0;
int atSameRank = 1;
DataView dv = new DataView(dt, "", "ObtainedMarks desc", DataViewRowState.CurrentRows);
for(int x = 0; x < dv.Count; x++)
{
int currentMark = Convert.ToInt32(dv["ObtainedMarks"]);
if(currentMark != lastMark)
{
lastMark = currentMark;
currentRank = currentRank + atSameRank;
atSameRank = 0;
}
else
atSameRank++;
dv[x].Row["Rank"] = currentRank;
}
WARNING, I am not at a PC where I could test it.

how to perform groupby in linq on DataTable inside vb code?

How do I perform group in LINQ inside vb code (dot.net v4.0) with DataTable and sum on the group?
In the sample below I need to add group by GroupName, ProductName and perform sum on QTY. The columns, order and where should remain as in sample, I just need to add the group and sum. The format should remain the same (getting row using e("FieldName")).
Dim ordersTable As DataTable = _dsProd.Tables("tblProductSummary")
Dim query =
(From e In ordersTable
Where (e("Type").ToString() = "1" Or IsDBNull(e("Type")))
Order By e("GroupSortOrder") Ascending, e("ProductName")
Select
GroupName = e("GroupName"),
ProductName = e("ProductName"),
QTY = e("QTY"),
Type= e("Type")
)
Dim query =
(From e In ordersTable
Where (e("Type").ToString() = "1" Or IsDBNull(e("Type")))
Order By e("GroupSortOrder") Ascending, e("ProductName")
Group e By Key = New With {
.ProductName = e("ProductName"),
.GroupName = e("GroupName")
} Into Group
Select New With {
.ProductName = Key.ProductName,
.GroupName = Key.GroupName,
.Sum = Group.Sum(Function(x) x("QTY"))
})

Copy rows between two datatable VB.net

I have two datatable how i could copy targeted rows index to another datatable in the same index, Please check below code.
Dim datatable1 As DataTable = GetEmployeeSummary()
Dim datatable2 As DataTable = GetEmployees()
For i As Integer = 0 To datatable1.Rows.Count - 1 'Datatable1.rows.count = datatable2.rows.count
Select Case i
Case 1, 5, 6, 19, 24
datatable2.Rows(i) = datatable2.Rows(i) 'how i could copy targeted rows index to another datatable in the same index
End Select
Next
You can use the DataRow.ItemArray if both tables have the same columns:
For i As Int32 = 0 To datatable1.Rows.Count - 1
Select Case i
Case 1, 5, 6, 19, 24
If datatable2.Rows.Count - 1 >= i Then
datatable2.Rows(i).ItemArray = datatable1(i).ItemArray
Else
Dim row = datatable2.Rows.Add()
row.ItemArray = datatable1(i).ItemArray
End If
End Select
Next
I recommend of using ImportRow. It will copy the whole row into your DataTable. So Your code would be like below.
Dim datatable1 As DataTable = GetEmployeeSummary()
Dim datatable2 As DataTable = GetEmployees()
For i As Integer = 0 To datatable1.Rows.Count - 1
Select Case i
Case 1, 5, 6, 19, 24
datatable2.ImportRow(datatable2.Rows(i))
End Select
Next