View Full Version : VBA for Sorting Table
omegaboost
12-02-2015, 04:51 AM
Dear All,
How to make the VBA for the sorting data from Input Table with there is no duplication and make the total for each Code. The sorting data will be like in sorting table.
for the further details I attach the file.
Thank you
Omegaboost14857
Leith Ross
12-04-2015, 03:37 PM
Hello VBAX Newbie,
This was a rather complex sorting operation. I rewrote this macro four times to make it easy to allow for more code columns and keep it fast. The macros below have been added to the attached workbook along with a button to run the main macro.
The sorted data is output the "Sorting Table". The macro can be changed to output the sorted data anywhere in the workbook. With a slight modification, the sorted data can overwrite the original data if needed.
Module1 Macro Code
Private TableRng As Range
Public Sub SortData()
Dim Cell As Range
Dim colCount As Long
Dim Data As Variant
Dim EntryData As Variant
Dim EntryDates As New Collection
Dim j As Long
Dim RngBeg As Range
Dim RngEnd As Range
Dim RngOut As Range
Dim Wks As Worksheet
' Save the Table's range of cells in the object variable TableRng.
Set Wks = Worksheets("Sheet1")
Set RngBeg = Wks.Range("A4:E4")
Set RngEnd = Wks.Cells(Rows.Count, RngBeg.Column).End(xlUp)
If RngEnd.Row < RngBeg.Row Then Exit Sub
Set TableRng = Wks.Range(RngBeg, RngEnd)
Application.ScreenUpdating = False
Set RngOut = Wks.Range("H4:L4")
colCount = RngOut.Columns.Count
' Create a collection of unique Entry Dates.
For Each Cell In TableRng.Columns(1).Cells
On Error Resume Next
EntryDates.Add Cell.Value, Cell.Text
On Error Resume Next
Next Cell
For Each EntryDate In EntryDates
Data = GetDataByDate(EntryDate)
RngOut.Cells(1, 1).Resize(RowSize:=UBound(Data, 1) + 1).Value = EntryDate
For j = 0 To UBound(Data, 1)
RngOut.Offset(j, 1).Resize(1, colCount - 1).Value = Data(j)
Next j
Set RngOut = RngOut.Offset(j, 0)
Next EntryDate
Application.ScreenUpdating = True
End Sub
Private Function GetDataByDate(ByVal EntryDate As Date)
Dim Amount1 As Long
Dim Amount2 As Long
Dim c As Variant
Dim Cell As Range
Dim colArray As Variant
Dim Data As Variant
Dim Dict As Object
Dim Key As Variant
Dim n As Long
Dim r As Long
Dim RngBeg As Range
Dim RngEnd As Range
Dim Wks As Worksheet
'EntryDate = DateValue("December 01, 2015")
' Relative Amount column numbers in the table. The last 2 rightmost columns.
Amount2 = TableRng.Columns.Count
Amount1 = Amount2 - 1
' Relative Table column numbers for the Date, Code1, and Code2. More Code columns can be added if needed.
colArray = Array(1, 2, 3)
Set Dict = CreateObject("Scripting.Dictionary")
' Check each Code column for matching dates.
For c = 1 To UBound(colArray)
For Each Cell In TableRng.Columns(colArray(0)).Cells
If Cell = EntryDate Then
' Convert absolute Worksheet row number to relative Table row number.
r = Cell.Row - TableRng.Row + 1
Key = Trim(TableRng.Cells(r, colArray(c)))
If Key <> "" Then
If Not Dict.Exists(Key) Then
' Create a new output array for the code.
ReDim Data(3)
Select Case c
Case 1: Data(0) = Key: Data(1) = Empty
Case 2: Data(0) = Empty: Data(1) = Key
End Select
Data(2) = TableRng.Cells(r, Amount1).Value
Data(3) = TableRng.Cells(r, Amount2).Value
Dict.Add Key, Data
Else
' Accumulate the amount columns for the code.
Data = Dict(Key)
Data(2) = Data(2) + TableRng.Cells(r, Amount1).Value
Data(3) = Data(3) + TableRng.Cells(r, Amount2).Value
Dict(Key) = Data
End If
End If
End If
Next Cell
Next c
' Return a Variant Array of all Codes and Amounts for the given date.
GetDataByDate = Dict.Items
End Function
I'd say:
Sub M_snb()
sn = Sheet1.Cells(4, 1).CurrentRegion
With CreateObject("scripting.dictionary")
For j = 3 To UBound(sn)
c00 = sn(j, 1) & "_" & sn(j, 2) & sn(j, 3)
If .exists(c00) Then
sp = .Item(c00)
sp(3) = sp(3) + sn(j, 4)
sp(4) = sp(4) + sn(j, 5)
Else
sp = Array(1 * CDate(sn(j, 1)), sn(j, 2), sn(j, 3), sn(j, 4), sn(j, 5))
End If
.Item(sn(j, 1) & "_" & sn(j, 2) & sn(j, 3)) = sp
Next
Sheet1.Cells(20, 1).Resize(.Count, 5) = Application.Index(.items, 0, 0)
End With
End Sub
omegaboost
12-05-2015, 07:46 AM
Dear All,
Once again thank you for kind response. Just need more favor to how to modify the VBA code in case the column for Amount 1 and Amount2 in the Input Table is located not next to each other and also in Sorting Table columns are not located next to each other. In terms of how to customize the layout of the column in VBA code as in the file (attached).
Thank you
Omegaboost 14886
Why don't you adapt the datastructure ?
Leith Ross
12-05-2015, 02:01 PM
Hello omegaboost,
Here is the updated macro code and workbook.
Private TableRng As Range
Public Sub SortData()
Dim Cell As Range
Dim colCount As Long
Dim colOutput As Variant
Dim Data As Variant
Dim EntryData As Variant
Dim EntryDates As New Collection
Dim j As Long
Dim n As Long
Dim RngBeg As Range
Dim RngEnd As Range
Dim RngOut As Range
Dim Wks As Worksheet
' Save the Table's range of cells in the object variable TableRng.
Set Wks = Worksheets("Sheet1")
Set RngBeg = Wks.Range("A4:G4")
Set RngEnd = Wks.Cells(Rows.Count, RngBeg.Column).End(xlUp)
If RngEnd.Row < RngBeg.Row Then Exit Sub
' Offsets from first cell in Table to the Output Columns.
colOutput = Array(0, 1, 2, 6, 9) ' Date, Code1, Code2, Amount1, Amount2
Set TableRng = Wks.Range(RngBeg, RngEnd)
Application.ScreenUpdating = False
Set RngOut = Wks.Range("J4:S4")
colCount = RngOut.Columns.Count
' Create a collection of unique Entry Dates.
For Each Cell In TableRng.Columns(1).Cells
On Error Resume Next
EntryDates.Add Cell.Value, Cell.Text
On Error Resume Next
Next Cell
For Each EntryDate In EntryDates
Data = GetDataByDate(EntryDate)
RngOut.Cells(1, 1).Resize(RowSize:=UBound(Data, 1) + 1).Value = EntryDate
For j = 0 To UBound(Data, 1)
n = 0
For k = 1 To UBound(colOutput)
RngOut.Cells(j + 1, 1).Offset(0, colOutput(k)).Value = Data(j)(n)
n = n + 1
Next k
Next j
Set RngOut = RngOut.Offset(j, 0)
Next EntryDate
Application.ScreenUpdating = True
End Sub
Private Function GetDataByDate(ByVal EntryDate As Date)
Dim Amount1 As Long
Dim Amount2 As Long
Dim c As Variant
Dim Cell As Range
Dim colArray As Variant
Dim Data As Variant
Dim Dict As Object
Dim Key As Variant
Dim n As Long
Dim r As Long
Dim RngBeg As Range
Dim RngEnd As Range
Dim Wks As Worksheet
'EntryDate = DateValue("December 01, 2015")
' Relative Amount column numbers in the table. The last 2 rightmost columns.
Amount2 = TableRng.Columns.Count
Amount1 = Amount2 - 2
' Relative Table column numbers for the Date, Code1, and Code2. More Code columns can be added if needed.
colArray = Array(1, 2, 3)
Set Dict = CreateObject("Scripting.Dictionary")
' Check each Code column for matching dates.
For c = 1 To UBound(colArray)
For Each Cell In TableRng.Columns(colArray(0)).Cells
If Cell = EntryDate Then
' Convert absolute Worksheet row number to relative Table row number.
r = Cell.Row - TableRng.Row + 1
Key = Trim(TableRng.Cells(r, colArray(c)))
If Key <> "" Then
If Not Dict.Exists(Key) Then
' Create a new output array for the code.
ReDim Data(3)
Select Case c
Case 1: Data(0) = Key: Data(1) = Empty
Case 2: Data(0) = Empty: Data(1) = Key
End Select
Data(2) = TableRng.Cells(r, Amount1).Value
Data(3) = TableRng.Cells(r, Amount2).Value
Dict.Add Key, Data
Else
' Accumulate the amount columns for the code.
Data = Dict(Key)
Data(2) = Data(2) + TableRng.Cells(r, Amount1).Value
Data(3) = Data(3) + TableRng.Cells(r, Amount2).Value
Dict(Key) = Data
End If
End If
End If
Next Cell
Next c
' Return a Variant Array of all Codes and Amounts for the given date.
GetDataByDate = Dict.Items
End Function
omegaboost
12-06-2015, 02:06 AM
Dear All,
Thank you for the helping. To answer why I did not adapt the data structure is because I want to learn to be able to understand the code further and if one day there is the same problem, I can handle it. Of course the first thing I do is create a data structure in accordance with the code.
Best Regards
Omegaboost
Structuring precedes coding....
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.