I am using a barcode scanner to do inventory with large quantities and I want to enter the data into excel. I can change the way that the scanner behaves after each scan to do things like tab, return, etc. but my big problem is that in order to efficiently provide the quantity I have to scan the item code (7 digits) and then scan the quantities from 0 to 9 in succession. Such that 548 is really 5, 4, 8 and when using excel it puts each number into a new cell. What I would like to do, but don't have the VBA chops to do it is to have excel check to see if the length is 7 digits or one digit. For each one digit number it should move the number to the next cell in the same row as the previous 7 digit number such that each successive one digit number is combined as if excel were concatenating the cells. Then it should delete the single digits in the original column and have the next row start with the 7 digit barcode number.
I hope this makes sense.
Example:
7777777
3
4
5
7777778
4
5
6
7777779
7
8
9
Should become:
| 7777777 | 345 |
| 7777778 | 456 |
| 7777779 | 789 |
Thanks!!
I set up my worksheet like this:
then ran the below code
Sub Digits()
Application.ScreenUpdating = False
Dim i&, r As Range, j&
With Columns("B:B")
.ClearContents
.NumberFormat = "#"
End With
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Set r = Cells(i, 1)
If Len(r) = 7 Then
j = 1
Do Until ((Len(r.Offset(j, 0).Text) = 7) Or (IsEmpty(r.Offset(j, 0))))
Cells(i, 2) = CStr(Cells(i, 2).Value) & CStr(r.Offset(j, 0))
j = j + 1
Loop
End If
Set r = Nothing
Next
For i = Cells(Rows.Count, 1).End(xlUp).Row To 1 Step -1
If Len(Cells(i, 1)) < 7 Then Rows(i & ":" & i).Delete
Next i
Columns.AutoFit
Application.ScreenUpdating = True
End Sub
and the results Ive got:
This is what I did with what you started but I think your newer solution will work better. Thank you so much mehow!
Sub Digits()
Application.ScreenUpdating = False
Dim i, arr, r As Range
Dim a, b, c, d, e
Dim y
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Set r = Cells(i, 1)
Set a = Cells(i + 1, 1)
Set b = Cells(i + 2, 1)
Set c = Cells(i + 3, 1)
Set d = Cells(i + 4, 1)
Set e = Cells(i + 5, 1)
If Len(a) = 7 Then
y = 0
ElseIf Len(b) = 7 Then
y = 1
ElseIf Len(c) = 7 Then
y = 2
ElseIf Len(d) = 7 Then
y = 3
ElseIf Len(e) = 7 Then
y = 4
Else:
y = 0
End If
If Len(r) = 7 Then
arr = Range("A" & i & ":A" & i + y).Value
Range("B" & i & ":F" & i) = WorksheetFunction.Transpose(arr)
End If
Next
Cells.Replace "#N/A", "", xlWhole
Application.ScreenUpdating = True
End Sub
Related
Please have a look at the following given code. It does the work but the code gives the values including the duplicates. (see the output)
I couldn't figure out how to extract unique vales instead of duplicates.
S.No Values
1 99.501
2 99.441
3 99.346
4 99.683
5 99.683
6 99.941
7 99.326
8 99.315
9 99.326
10 99.564
11 99.565
12 99.513
13 99.396
14 99.676
15 99.083
16 99.083
17 98.886
18 99.129
19 99.129
20 99.73
My code:
Sub MaxMin()
Dim Rng As Range, Dn As Range, Lg As String
Dim n As Long, c As Long, nRay As Variant
Dim Sm As String, Sp As Variant, ac As Long
Dim col As Integer, R As Long, t
Set Rng = Range(Range("b2"), Range("b" & Rows.Count).End(xlUp))
For n = 1 To 5
Lg = Lg & IIf(Lg = "", Application.Large(Rng, n), "," _
& Application.Large(Rng, n))
Sm = Sm & IIf(Sm = "", Application.Small(Rng, n), "," _
& Application.Small(Rng, n))
Next n
Sp = Array(Split(Lg, ","), Split(Sm, ","))
ReDim Ray(1 To 11, 1 To 4)
Ray(1, 1) = "S.No"
Ray(1, 2) = "Max"
Ray(1, 3) = "S.No"
Ray(1, 4) = "Min"
For ac = 0 To 1
col = IIf(ac = 0, 1, 3)
c = 0
nRay = Range(Range("A2"), Range("b" & Rows.Count).End(xlUp)).Resize(, 2)
c = 1
For n = 0 To 4
For R = 1 To UBound(nRay, 1)
If Not IsEmpty(nRay(R, 2)) And nRay(R, 2) = Val(Sp(ac)(n)) Then
c = c + 1
Ray(c, col) = nRay(R, 1)
Ray(c, col + 1) = nRay(R, 2)
nRay(R, 2) = ""
Exit For
End If
Next R
Next n
Next ac
Range("F1").Resize(6, 4).Value = Ray
End Sub
Output:
S.No Max S.No Min
6 99.941 17 98.886
20 99.73 15 99.083
4 99.683 16 99.083
5 99.683 18 99.129
14 99.676 19 99.129
The modified code should not include "duplicate" only "unique" 5 max and 5 min values with their index positions.
You can use Dictionary Object to get such results which QHarr is referring to like below.
Public Sub GetMinMax()
Dim objDict As Object
Dim i As Long
Set objDict = CreateObject("Scripting.Dictionary")
'\\ Add uniques to list
For i = 2 To Range("B" & Rows.Count).End(xlUp).Row
If Not objDict.exists(Range("B" & i).Value) Then objDict.Add Range("B" & i).Value, Range("A" & i).Value
Next
'\\ Populate output columns
Range("F1").Resize(1, 4).Value = Array("S.No.", "Max", "S.No.", "Min")
For i = 1 To 5
Range("G" & i + 1).Value = Application.Large(objDict.keys, i)
Range("F" & i + 1).Value = objDict.Item(Range("G" & i + 1).Value)
Range("I" & i + 1).Value = Application.Small(objDict.keys, i)
Range("H" & i + 1).Value = objDict.Item(Range("I" & i + 1).Value)
Next
End Sub
I am using the code below and it works for filtering the unique name and totalting the value field. I recently have a need to expand upon the filtering of unique names to include other columns in the criteria. Please see the example output I am looking for. Any help would be appreciated.
Sub SUM()
Dim i, j, k As Integer
i = 2
j = 2
Range("D1").Value = "NAME"
Range("E1").Value = "VALUE"
'copy the first value of column A to column D
Range("D2").Value = Range("A2").Value
'cycle to read all values of column B and sum it to column E; will run until find a blank cell
While Range("A" & i).Value <> ""
'this check if actual value of column A is equal to before value of column A, if true just add the column B value to E
'else, look for the row in column D where is the same value of column A, if it doesn't exist code create the value
'in column D and E
If Range("A" & i).Value = Range("A" & i - 1).Value Then
Range("E" & j).Value = Range("E" & j).Value + Range("B" & i).Value
Else
flag = 1
While Range("D" & flag).Value <> ""
If Range("A" & i).Value = Range("D" & flag).Value Then
j = flag
Range("E" & j).Value = Range("E" & j).Value + Range("B" & i).Value
flag = Range("D1").End(xlDown).Row
Else
j = 0
End If
flag = flag + 1
Wend
If j = 0 Then
Range("D1").End(xlDown).Offset(1, 0).Value = Range("A" & i).Value
Range("E1").End(xlDown).Offset(1, 0).Value = Range("B" & i).Value
j = Range("E1").End(xlDown).Row
End If
End If
i = i + 1
Wend
MsgBox "End"
End Sub
Currently outputs like this:
Name Value Name Sum
A 1 A 13
A 2 B 7
B 1 C 3
B 3
C 2
A 1
B 2
A 3
B 1
A 2
A 4
C 1
I would like to have it export data like this example:
Name Code Date Value Name Code Date Sum
A 101 3/10/17 1 A 101 3/10/17 9
A 101 3/10/17 2 A 102 3/10/17 4
B 102 3/10/17 1 B 101 3/10/17 3
B 101 3/10/17 3 B 102 3/10/17 2
C 102 3/8/17 2 B 101 3/8/17 2
A 102 3/10/17 1 C 102 3/8/17 2
B 101 3/8/17 2 C 102 3/10/17 1
A 102 3/10/17 3
B 102 3/10/17 1
A 101 3/10/17 2
A 101 3/10/17 4
C 102 3/10/17 1
As long as your columns go A,B,C,D then F,G,H,I then below code should work. Let me know if it works for you.
Sub CountCodes()
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Dim wbk As Workbook
Dim ws As Worksheet
Dim wsRow As Long, newRow As Long
Dim Names() As String
Dim Found As Boolean
Dim x As Integer, y As Integer, z As Integer, myCount As Integer, mySum As Integer
Dim Cell As Range
Set wbk = ThisWorkbook
Set ws = wbk.Worksheets(1)
ReDim Names(0 To 0) As String
ReDim Codes(0 To 0) As String
ReDim Dates(0 To 0) As String
newRow = 1
With ws
'Find last row of data
wsRow = .Range("A" & .Rows.Count).End(xlUp).Row
'Loop through Column A to fill array
For Each Cell In .Range(.Cells(2, 1), .Cells(wsRow, 1))
'Fill Names array
Found = (IsInArray(Cell.Value2, Names) > -1)
If Found = False Then
Names(UBound(Names)) = Cell.Value2
If Cell.Row <> wsRow Then
ReDim Preserve Names(0 To UBound(Names) + 1) As String
End If
End If
'Fill Codes array
Found = (IsInArray(Cell.Offset(0, 1).Value2, Codes) > -1)
If Found = False Then
Codes(UBound(Codes)) = Cell.Offset(0, 1).Value2
If Cell.Row <> wsRow Then
ReDim Preserve Codes(0 To UBound(Codes) + 1) As String
End If
End If
'Fill Dates array
Found = (IsInArray(Cell.Offset(0, 2).Value2, Codes) > -1)
If Found = False Then
Dates(UBound(Dates)) = Cell.Offset(0, 2).Value
If Cell.Row <> wsRow Then
ReDim Preserve Codes(0 To UBound(Dates) + 1) As String
End If
End If
Next
'Add Autofilter if off
If .AutoFilterMode = False Then
.Range("A1").AutoFilter
End If
For x = LBound(Names) To UBound(Names)
.Range("A1").AutoFilter Field:=1, Criteria1:=Names(x)
For y = LBound(Codes) To UBound(Codes)
.Range("B1").AutoFilter Field:=2, Criteria1:=Codes(y)
For z = LBound(Dates) To UBound(Dates)
.Range("C1").AutoFilter Field:=3, Criteria1:=Dates(z)
For Each Cell In .Range("A1:A" & wsRow).SpecialCells(xlCellTypeVisible)
myCount = myCount + 1
Next
If myCount > 1 Then
For Each Cell In .Range("D2:D" & wsRow).SpecialCells(xlCellTypeVisible)
mySum = mySum + Cell.Value2
Next
'Find last row in new data
newRow = newRow + 1
.Cells(newRow, 6) = Names(x)
.Cells(newRow, 7) = Codes(y)
.Cells(newRow, 8) = Dates(z)
.Cells(newRow, 9) = mySum
End If
myCount = 0
mySum = 0
Next z
Next y
Next x
.ShowAllData
End With
Erase Names
Erase Codes
Erase Dates
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
'http://stackoverflow.com/questions/10951687/how-to-search-for-string-in-an-array
'Boolean = (IsInArray(StringToFind, ArrayToSearch) > -1)
Dim i As Long
' default return value if value not found in array
IsInArray = -1
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i), vbTextCompare) = 0 Then
IsInArray = i
Exit For
End If
Next i
End Function
I used a pivot table in Excel 2016 to generate this view, since you are not opposed to using a Pivot Table. If Excel can do this out of the box, and you are happy with how it looks and behaves, there is no real need for custom VBA in this case.
Just do the following:
Highlight your data, then insert > pivot table
I placed the pivot table in cell F1 of Sheet 1
Add Name, Code, and Date to the Rows of the pivot table
Add Value to the Values of the pivot table. It should default to Sum.
Click on the pivot table, then in the pivot table tools > design tab in the ribbon, go to the "Layout" ribbon group:
On the Report Layout Dropdown:
Click "Show in Tabular Form"
Click "Repeat All Item Labels"
On the Subtotals Dropdown:
Click "Do Not Show Subtotals"
On the Grand totals Dropdown:
Click "off for rows and columns"
You could use Dictionary object:
Option Explicit
Sub ListTotals()
Dim c As Range, dataRng As Range
Dim key As Variant
Set dataRng = Range("A2", Cells(Rows.Count, 1).End(xlUp))
With CreateObject("Scripting.Dictionary")
For Each c In dataRng
key = Join(c.Resize(,3), "|")
.Item(key) = .Item(key) + c.Offset(,4)
Next c
With dataRng.Resize(.Count)
.Offset(,5) = Application.Transpose(.Keys)
.Offset(,8) = Application.Transpose(.Items)
.Offset(,5).TextToColumns DataType:=xlDelimited, Other:=True, OtherChar:="|", FieldInfo:= Array(Array(1, 2), Array(3, 3))
End With
End With
End Sub
I am doing automation on matching Data form row Data1 to Data 2,
I was done by looping statement but the problem is take much time, when number of row increase
For that reason i planed do by vlookup, In vlookup only return first occurrence cell but i need to find all match cell and highlighted matched row ,which i show in figure.
Working with cells directly reduces the code performance. Try to set Data1 and Data2 to arrays and work with arrays.
Something like this:
With ActiveSheet
arr = .Range(.[A2], .Cells(.Rows.Count, "A").End(xlUp)).Value
arr2 = .Range(.[D2], .Cells(.Rows.Count, "D").End(xlUp)).Value
For i& = 1 To UBound(arr)
For j& = 1 To UBound(arr2)
If arr(i, 1) = arr2(j) Then
...
End If
Next j
Next i
End With
Hope you are looking for this
Sub testvlookup()
Dim lastrow, lastrowdata, incre, i, j As Long
lastrow = Range("A" & Rows.Count).End(xlUp).Row
lastrowdata = Range("D" & Rows.Count).End(xlUp).Row
incre = 6
For i = 2 To lastrow
For j = 2 To lastrowdata
If Range("A" & i).Value = Range("D" & j).Value Then
Range("D" & j, "G" & j).Interior.ColorIndex = incre
End If
Next j
incre = incre + 1
Next i
End Sub
I don't see the point why it should be to slow for many rows, it would be good to have more informations about that.
I would do it like the others, takes ~1 sec with 100000 comparisons.
Dim i As Integer
Dim b As Integer
i = 1
While i < 20000
Range("A1:A5").Copy Range(Cells(i, 4), Cells(i + 5, 4))
i = i + 5
Wend
MsgBox ("hi")
i = 1
While i < 7
b = 3
While b < 20000
If Cells(i, 1).Value = Cells(b, 4).Value Then
Cells(b, 4).Interior.ColorIndex = i
End If
b = b + 1
Wend
i = i + 1
Wend
End Sub
I think what I'm trying to do is pretty basic, but I'm brand new to VBA so I'm getting stuck and the answers I've found are close, but not quite right.
I have a list of row entries, like this:
1 4 32 2 4
2 6 33 1 3
1 4 32 2 4
4 2 30 1 5
Notice that rows 1 and 3 are duplicates. I'd like to only have a single instance of each unique row but I don't want to just delete the duplicates, I want to report how many of each type there are. Each row represents an inventory item, so deleting duplicate entries without indicating total quantity would be very bad!
So, my desired output would look something like this, where the additional 6th column counts the total number of instances of each item:
1 4 32 2 4 2
2 6 33 1 3 1
4 2 30 1 5 1
My data sets are larger than just these 5 columns, they're closer to 10 or so, so I'd like to put that last column at the end, rather than to hardcode it to the 6th column (i.e., column "F")
Update:
I found some code that worked with minor tweaking, and it worked this morning, but after messing around with some other macros, when I came back to this one it was telling me that I have a "compile error, wrong number of arguments or invalid property assignment" and it seemed to be unhappy with the "range". Why would working code stop working?
Sub mcrCombineAndScrubDups2()
For Each a In range("A1", Cells(Rows.Count, "A").End(xlUp))
For r = 1 To Cells(Rows.Count, "A").End(xlUp).Row - a.Row
If a = a.Offset(r, 0) And a.Offset(0, 1) = a.Offset(r, 1) And a.Offset(0, 2) = a.Offset(r, 2) Then
a.Offset(0, 4) = a.Offset(0, 4) + a.Offset(r, 4)
a.Offset(r, 0).EntireRow.Delete
r = r - 1
End If
Next r
Next a
End Sub
Assuming that your data starts from A1 on a worksheet named ws1, the following code removes the duplicated rows. Not by shifting the whole table but deleting the entire row.
Sub deletedupe()
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim row1 As String
Dim row2 As String
i = 1
j = 1
k = 1
Do While Sheets("ws1").Cells(i, 1).Value <> ""
row1 = ""
j = 1
Do While Sheets("ws1").Cells(i, j).Value <> ""
row1 = row1 & Sheets("ws1").Cells(i, j).Value & " "
j = j + 1
Loop
k = i + 1
Do While Sheets("ws1").Cells(k, 1).Value <> ""
row2 = ""
j = 1
Do While Sheets("ws1").Cells(k, j).Value <> ""
row2 = row2 & Sheets("ws1").Cells(k, j).Value & " "
j = j + 1
Loop
If row1 = row2 Then
Sheets("ws1").Rows(k).EntireRow.Delete
Else
k = k + 1
End If
Loop
i = i + 1
Loop
End Sub
I have a column which consists of 3 digit codes referring to a branch. If a person is working in multiple departments, then he/she will have multiple codes referred in that column. Below is what it would look like.
Name | Branch
ABC | 423
MNO | 367325
XYZ | 414426429
I want it to look like this.
Name | Branch
ABC | 423
MNO | 367
MNO | 325
XYZ | 414
XYZ | 426
XYZ | 429
I want to extract the value of the cell, suppose let's say the string length is 9, then that person works for 3 branches. I want to extract those 3 values and duplicate the entire row with each row containing one branch number.
A few pointers : No person can work for more than 3 branches(so maximum string length will be 9). There are about 20 columns. The column which contains the branch codes is always the same i.e. column G. The column also has empty cells and other string values like 'BIKCJHGT'. The entire column is formatted as text.
Can any one please give me the VBA code to accomplish this?
Here is the code I've used. It hasn't thrown any errors, but it's not working either.
Option Explicit
Sub MultiRecords()
Dim b As Workbook
Set b = Workbooks.Open("C:\Users\uspola00\Desktop\Headcount_Final.xlsx")
ActiveWorkbook.Sheets("Headcount").Activate
ActiveSheet.Range("G1").Select
Dim ws As Worksheet
Set ws = Sheets("Headcount")
Dim intInsertRows As Integer
Dim i As Long
i = 1
Application.ScreenUpdating = False
Do Until i > ws.Range("G" & Rows.Count).End(xlUp).Row
Dim str As String
str = LTrim(RTrim(ws.Range("G" & i)))
If Len("G" & i) = 9 Then
intInsertRows = 2
Range("G" & i + 1 & ":G" & i + intInsertRows).EntireRow.Insert
Range("A" & i & ":N" & (i + intInsertRows)).FillDown
Range("G" & (i + intInsertRows)).Value = Right(str, 3)
Range("G" & i + 1).Value = Mid(str, 4, 3)
Range("G" & i).Value = Left(str, 3)
i = i + intInsertRows
ElseIf Len("G" & i) = 6 Then
intInsertRows = 1
Range("G" & i & ":G" & i + intInsertRows).EntireRow.Insert
Range("A" & i & ":N" & (i + intInsertRows)).FillDown
Range("G" & i + intInsertRows).Value = Right(str, 3)
Range("G" & i).Value = Left(str, 3)
i = i + intInsertRows
ElseIf Len("G" & i) = 3 Then
intInsertRows = 0
i = i + intInsertRows
ElseIf IsEmpty(Range("G" & i)) Then
i = i + 0
End If
i = i + 1
Loop
End Sub
Try this:
Sub MultiRecords()
Dim b As Workbook
Dim ws As Worksheet
Dim c As Range, v, i As Long
Set b = Workbooks.Open("C:\Users\uspola00\Desktop\Headcount_Final.xlsx")
Set ws = b.Sheets("Headcount")
Set c = ws.Cells(Rows.Count, "G").End(xlUp)
Do
v = Trim(c.Value)
If v Like "######" Or v Like "#########" Then
i = Len(v) / 3
c.Offset(1, 0).Resize(i - 1).EntireRow.Insert
c.Resize(i).EntireRow.FillDown
c.Value = Left(v, 3)
c.Offset(1, 0).Value = Mid(v, 4, 3)
If Len(v) = 9 Then c.Offset(2, 0).Value = Right(v, 3)
End If
If c.Row = 1 Then Exit Do
Set c = c.Offset(-1, 0)
Loop
End Sub