Copy rows between two datatable VB.net - 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

Related

How to change all the values in the column in datagridview

I want to set the value in the data grid view if the column "is_active" have the value of 0 then it show "ACTIVE" not 0.
MY CODE:
Dim dt As DataTable
dt = exec("select * from tbl_credentials where is_active = 1 and is_status = 2")
If DataGridView1.Columns(3).ToString = 1 Then
dt.Columns(3).value = "ACTIVE"
End If
DataGridView1.DataSource = dt
use select CASE :
Dim dt As DataTable
dt = exec("select username,password, CASE is_active WHEN 0 then 'ACTIVE' ELSE '' END from tbl_credentials")
DataGridView1.DataSource = dt

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

vb.net array.sort() parameters why 1 short?

I'm sorting an array using code like this:
Array.Sort(arr, 0, intEndingPosition, New myIComparer)
I want the sorting to start with index 0 and end with index intEndingPosition. However, the last element arr(intEndingPosition) was left out and did not get sorted. Why?
intEndingPosition is calculated beforehand like this:
Dim StringOfConcern As String
Dim OneChar(65534), FrqOne(65534) As String
Dim CntNewOnes, CntRptOnes As Integer
Dim c As Char
Dim i, j As Integer
Dim isNew As Boolean
StringOfConcern = TextBox1.Text
OneChar(0) = CStr(StringOfConcern(0))
FrqOne(0) = 1
i = 0
j = 0
For Each c In StringOfConcern.Substring(1)
isNew = True
For j = 0 To i Step 1
If CStr(c) = OneChar(j) Then
isNew = False
FrqOne(j) += 1
Exit For
End If
Next j
If isNew = True Then
i += 1
OneChar(i) = CStr(c)
FrqOne(i) = 1
End If
Next c
CntNewOnes = i + 1
CntRptOnes = 0
For i = 0 To CntNewOnes - 1 Step 1
If FrqOne(i) > 1 Then CntRptOnes += 1
Next i
The sorting follows here. The code in my original question is only illustrative. The actual sorting is:
Array.Sort(FrqOne, OneChar, 0, CntNewOnes - 1)
Array.Reverse(FrqOne, 0, CntNewOnes - 1)
Array.Reverse(OneChar, 0, CntNewOnes - 1)
Note the method declaration for Array.Sort
Public Shared Sub Sort (
array As Array,
index As Integer,
length As Integer,
comparer As IComparer
)
The third parameter is the number of elements in the range to sort (length) not the end index as you suggest.
So let's assume for a minute that your intEndingPosition is 4. This means you're expecting to sort 5 elements i.e. elements at indices 0, 1, 2, 3, 4. However, the number 4 is the length and not the end index thus you're only sorting elements at indices 0, 1, 2, 3.
This explains why you're observing that the elements being sorted is one shorter than you expected.
Put it simply the third parameter should specify the length of elements to sort and not the end index.
Another Example:
Consider the Substring method of the String class:
Public Function Substring (
startIndex As Integer,
length As Integer
) As String
Then assume we have this piece of code:
Dim temp As String = "testing"
Dim result As String = temp.Substring(0, 4)
result is now a string containing 4 characters as 4 in the Substring call indicates the length that should be retrieved as opposed to the end index.
Had 4 been the end index then you'd expect result to contain 5 characters.

Updating A DataGridView Cell Incrementally

I'm currently having a slight issue duplicating a row and incrementing the sequence number.
So based on a button click, this is how I'm duplicating row 0, duplicated only one time per click.
Dim dr As DataRow
For n As Integer = 0 To 0 ' how many dupes you want
dr = tbl.NewRow
For c As Integer = 0 To tbl.Columns.Count - 1 ' copy data from 0 to NewRow
dr.Item(c) = tbl.Rows(0).Item(c)
Next
tbl.Rows.Add(dr) ' add NewRow to datatable
Next n
Here's how I'm creating the sequence number, pads with leading zeros, which seems to increment, but only after I click the duplicate button, so essentially the last row added, it the duplicated row 0, but doesn't represent the new sequence number needed.
'UPDATE SEQUENCE NUMBER
i += 1
Dim value As Integer = i
Dim r As Integer
Dim decimalLength1 As Integer = value.ToString("D").Length + 7
Dim decimalLength2 As Integer = value.ToString("D").Length + 6
Dim decimalLength3 As Integer = value.ToString("D").Length + 5
Dim decimalLength4 As Integer = value.ToString("D").Length + 4
If i >= 0 And i <= 9 Then
'1 TO 9 FORMAT
DataGridView1.CurrentCell = DataGridView1.CurrentRow.Cells("sequence")
DataGridView1.Item(73, r).Value = value.ToString("D" + decimalLength1.ToString())
'Debug.Print(value.ToString("D" + decimalLength1.ToString()))
ElseIf i >= 10 And i <= 99 Then
'10 TO 99 FORMAT
DataGridView1.CurrentCell = DataGridView1.CurrentRow.Cells("sequence")
DataGridView1.Item(73, r).Value = value.ToString("D" + decimalLength2.ToString())
'Debug.Print(value.ToString("D" + decimalLength1.ToString()))
ElseIf i >= 100 And i <= 999 Then
'100 TO 999 FORMAT
DataGridView1.CurrentCell = DataGridView1.CurrentRow.Cells("sequence")
DataGridView1.Item(73, r).Value = value.ToString("D" + decimalLength3.ToString())
'Debug.Print(value.ToString("D" + decimalLength1.ToString()))
ElseIf i >= 1000 And i <= 9999 Then
'1000 TO 9999 FORMAT
DataGridView1.CurrentCell = DataGridView1.CurrentRow.Cells("sequence")
DataGridView1.Item(73, r).Value = value.ToString("D" + decimalLength4.ToString())
'Debug.Print(value.ToString("D" + decimalLength1.ToString()))
End If
Row 0 will always have a sequence number of 1, so in theory I need to start incrementing at 2.
Suggestions? Is there a better/cleaner way of doing this?
UPDATE 2
Dim startSeq As Integer = Convert.ToInt32(tbl.Rows(0).Item(73))
MsgBox("startSeq = " & startSeq)
For n As Integer = 0 To NumericUpDown1.Value - 1
MsgBox("n = " & n)
dr = tbl.NewRow
For c As Integer = 0 To tbl.Columns.Count - 1
dr.Item(c) = tbl.Rows(0).Item(c)
If c = "73" Then ' if this is the SEQ column,
' add the current seq val to the seq column
dr.Item(c) = (startSeq + n).ToString("00000000")
End If
Next c
tbl.Rows.Add(dr)
Next n
It seems like you should be able to add the sequencer as you create the duplicates. Perhaps make it a method and pass the index of the column which has the sequence string. Something like:
Private Sub DuplicateRows(ColIndx As Integer,
Dupes As Integer)
' start value is Row(0) + 1
Dim startSeq As Integer = Convert.ToInt32(tbl.Rows(0).Item(ColIndx )) + 1
For n As Integer = 0 to Dupes -1
dr = tbl.NewRow
For c As Integer = 0 To tbl.Columns.Count - 1
If c = ColIndx Then ' if this is the SEQ column,
' add the current seq val to the seq column
dr.Item(c) = (startSeq + n).ToString("00000000")
Else
' otherwise copy the data from Row(0)
dr.Item(c) = tbl.Rows(0).Item(c)
End If
Next c
tbl.Rows.Add(dr)
Next n
End Sub
This should initialize each new row with an incremented counter. Is there a better/cleaner way of doing this
a) you should be adding to the DataTable, not the DGV if it is bound
b) (startSeq + n).ToString("00000000") should work to do the padding etc instead of that ugly block of code.
c) Use Option Strict On. If c = "73" ... is nonsense which makes the compiler guess at your intentions. Its is bug food.
d) Hardcoding "73" may work this time, but previously you said it could be anywhere. The code below finds the sequence column based on the name so it can appear anywhere. Rather than a form level var, you could find it just before you make the dupes or even in the Dupes procedure.
e) Dim startSeq As Integer = Convert.ToInt32(tbl.Rows(0).Item(73)) if you examine the answer above, this should be ... + 1 to increment the first value.
Usage:
Private tbl As DataTable ' table loaded from flat file
Private SeqColIndex As Integer ' assigned somewhere to
' point to the "sequence" column
' method to load data
Dim connstr = "Provider=Microsoft.ACE.OLEDB.12.0;..."
Using cn As New OleDbConnection(connstr)
...
End Using
' FIND the sequence column for this session
For n = 0 To tbl.Columns.Count - 1
If tbl.Columns(n).ColumnName.ToLowerInvariant = "sequence" Then
SeqColIndex = n
Exit For
End If
Next
' later to add some rows
Private Sub ButtonAddRow_Click(...
DuplicateRows(SeqColIndex, NumericUpDown1.Value)
End Sub

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)