I have been asked to remake the excel workbook to index where we keep the items.
I have an excel sheet with a table ( excel table) that contains the information.
If the there the value in column 6 ="10" then that means the item is in box 10.
then I need to get the right shelve, this is found by the numbers in column 7 (shelve) and 8 (rack). subsequently the information about the item has to be put in another sheet which gives a visual representation of the box.
I am struggling to get the desired result, does anyone have some suggestions?
Sub box()
Dim rng As Range
For x = 1 To 12
Set rng = Sheets("Register").ListObject("Table1").Range(x, 8).Value
If Range("Table1").ListObject.Range(x, 6).Value = "10" Then
If Range("Table1").ListObject.Range(x, 7).Value = "1" Then
Sheets("box 10").Range(3, rng).Value = Range("Table1").ListObject.Range(x, 2).Value & Range("Table1").ListObject.Range(x, 3)
End If
End If
Next x
End Sub
Please, try the next code. It will iterate in the table DataBodyRange and build a sheet name obtained by concatenation of "Box " with value in table column 6 (in your workbook). If such a sheet does not exist, a warning message is sent and stops the code:
Option Explicit
Sub box()
Dim boxVal As String, tbl As ListObject, shBox As Worksheet, rngRef As Range, x As Long
Dim shelvNo As Long, rackNo As Long
Dim iRow As Long: iRow = 1 ' row where "rack" exist
Dim iCol As Long: iCol = 1 'column letter where "rack" exists (C:C)
Set tbl = Sheets("Register").ListObjects("Table1")
For x = 1 To tbl.DataBodyRange.Rows.Count 'on the frist row there are ABC, ABC etc.
If tbl.DataBodyRange.Cells(x, 1) = "" Then Exit For
boxVal = tbl.DataBodyRange.Cells(x, 6).Value
On Error Resume Next
Set shBox = Sheets("Box " & boxVal) 'set the sheet of the appropriate box 'set the sheet of the appropriate box
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
MsgBox "No sheet named """ & "box " & tbl.DataBodyRange.Cells(x, 6).Value & """ exists" & vbCrLf & _
"Please, create it and run the code again!": Exit Sub
End If
On Error GoTo 0
Set rngRef = shBox.Cells(iRow, iCol)
shelvNo = iRow + 1 + tbl.DataBodyRange.Cells(x, 7).Value
rackNo = iCol + tbl.DataBodyRange.Cells(x, 8).Value - 1
rngRef.Offset(shelvNo, rackNo).Value = tbl.DataBodyRange.Cells(x, 2).Value & " " & tbl.DataBodyRange.Cells(x, 3).Value
Next x
MsgBox "Ready..."
End Sub
Related
I have an excel file contains 20 columns and 100 rows, If the Value in A2= Reportable certain columns in excel are mandatory and similarly if A2 =Non-Reportable then certain other column values are mandatory, So need an VB script to check this condition if any of the mandatory column cell value is blank then on save of excel file throw an error message and error message should list all the missing column headers and rows. The script should validate all the rows, tried the below code, but not working and also i get mutiple error message instead of single error message
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim Cell As Range
Dim flag As Boolean
flag = False
If Cells(1, 1) = "" Then flag = True
For Each Cell In Range("B2:B3")
If Cell = "" Then
MsgBox ("Signoff is missing")
flag = True
Exit For
End If
Next Cell
For Each Cell In Range("D2:D3")
If Cell = "" Then
MsgBox ("tax Regime value is missing")
flag = True
Exit For
End If
Next Cell
For Each Cell In Range("E2:E3")
If Cell = "" Then
MsgBox ("Classification value is missing")
flag = True
Exit For
End If
Next Cell
Cancel = flag
End Sub
update - added error.txt as output
update2 - colour cells red and create error sheet
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim ws As Worksheet, lastrow As Long, ar(2)
Dim msg As String, c As String
Dim r As Long, i As Long, n As Long
ar(1) = Array("B", "D", "F") ' non-reportable columns
ar(2) = Array("C", "E", "G") ' reportable columns
Set ws = ActiveSheet
With ws
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For r = 2 To lastrow
.Rows(r).Cells.Interior.Pattern = xlNone
n = 0
If LCase(.Cells(r, "A")) = "non-reportable" Then
n = 1
ElseIf LCase(.Cells(r, "A")) = "reportable" Then
n = 2
End If
If n > 0 Then
For i = 0 To UBound(ar(n))
c = ar(n)(i)
If .Cells(r, c) = "" Then
.Cells(r, c).Interior.Color = RGB(255, 0, 0) ' red
msg = msg & vbLf & "Row " & r & " missing " & .Cells(1, c)
End If
Next
End If
Next
End With
Dim wsErr As Worksheet, arErr
If Len(msg) > 0 Then
' create error sheet
arErr = Split(msg, vbLf)
Set wsErr = Sheets.Add(after:=Sheets(Sheets.Count))
wsErr.Name = "Errors " & Format(Now(), "yyyy-mm-dd hhmmss")
wsErr.Cells(1, 1).Resize(UBound(arErr) + 1) = Application.Transpose(arErr)
Open "errors.txt" For Output As #1
Print #1, msg
Close #1
MsgBox "Missing data see error.txt", vbCritical
Cancel = True
Else
MsgBox "All good"
End If
End Sub
I am basically stuck in this VBA as I did not know how to lookup 2 cells and return with another cell value. It might be solve with reading project name to lookup first and then reading the week number to match and return the phase in grey area, but to get the 2 lookup together is difficult for me.
This is the first sheet where the input come in as week number and date in each phase
The second sheet will search the project number and week number, return the phase in column J and next.
Use a couple of Dictionary Objects as look-ups to the Project rows and Week columns.
Option Explicit
Sub Macro()
Const SHT_PRJ = "Project"
Const COL_ID_PRJ = "E"
Const COL_PH1 = "F" ' Phase 1
Const ROW_HDR_PRJ = 2 ' header
Const SHT_DEM = "Demand"
Const COL_ID_DEM = "D"
Const ROW_HDR_DEM = 1
Const MAX_PH = 6 ' phases 1 to 6
Dim wb As Workbook
Dim wsIn As Worksheet, wsOut As Worksheet
Dim cell As Range, rng As Range
Dim iRow As Long, iLastRow As Long, iCol() As Integer, iLastCol As Integer
Dim iColWk As Integer
Dim iColor As Variant, sWk As String, iPh As Integer
Set wb = ThisWorkbook
Set wsIn = wb.Sheets(SHT_PRJ)
Dim dict As Object, dictWk As Object, key
Set dict = CreateObject("Scripting.Dictionary")
Set dictWk = CreateObject("Scripting.Dictionary")
' build lookup to row for ID
iLastRow = wsIn.Cells(Rows.Count, COL_ID_PRJ).End(xlUp).Row
For iRow = ROW_HDR_PRJ + 1 To iLastRow
key = Trim(wsIn.Cells(iRow, COL_ID_PRJ))
If dict.exists(key) Then
MsgBox "Duplicate key " & key, vbCritical, "Row " & iRow
Exit Sub
ElseIf Len(key) > 0 Then
dict.Add key, iRow
End If
Next
' build look up to column for week
Set wsOut = wb.Sheets(SHT_DEM)
iLastCol = wsOut.Cells(ROW_HDR_DEM, Columns.Count).End(xlToLeft).Column
For Each cell In wsOut.Cells(ROW_HDR_DEM, 1).Resize(1, iLastCol)
key = Trim(cell.Value)
If dictWk.exists(key) Then
MsgBox "Duplicate week " & key, vbCritical, "Col " & cell.Column
Exit Sub
ElseIf Len(key) > 0 Then
dictWk.Add key, cell.Column
End If
Next
' update demand sheet
ReDim iCol(MAX_PH)
iLastRow = wsOut.Cells(Rows.Count, COL_ID_DEM).End(xlUp).Row
For Each cell In wsOut.Cells(ROW_HDR_DEM + 1, COL_ID_DEM).Resize(iLastRow)
iColor = cell.Interior.ColorIndex
key = Trim(cell.Value)
' each project
If Len(key) > 0 And iColor <> xlColorIndexNone Then '-4142
iRow = dict(key) ' row on project sheet
If iRow < 1 Then
MsgBox "ID " & key & " not found", vbCritical, _
wsOut.Name & " Row " & cell.Row
Exit Sub
Else
' get week numbers for each phase
For iPh = 1 To MAX_PH
sWk = wsIn.Cells(iRow, COL_PH1).Offset(0, 2 * (iPh - 1))
If Len(sWk) > 0 Then
' look up week to column
iCol(iPh) = dictWk(sWk)
If iCol(iPh) < 1 Then
MsgBox "Week " & sWk & " not found", vbCritical, _
wsOut.Name & " Row " & cell.Row
Exit Sub
Else
' update sheet
wsOut.Cells(cell.Row, iCol(iPh)) = "Phase " & iPh
End If
End If
Next
' fill in gaps with previous
For iColWk = iCol(1) To iCol(MAX_PH)
Set rng = wsOut.Cells(cell.Row, iColWk)
If rng.Value = "" Then
rng.Value = rng.Offset(0, -1).Value
End If
Next
End If
End If
Next
MsgBox dict.Count & " projects processed"
End Sub
I've written the below code to search for a value(Supplier Name) in sheet "Fusion" Column H in sheet "CX" column D. I'm also doing a check the other way around so if the same value(Supplier Name) in sheet CX is in sheet "Fusion". I'm not looking for an Exact match hence the use of Instr and doing the comparison both ways as i'm not sure how a user has entered the information in either sheet.
The data type in either cell should be text.
If a match is found then in the last column of sheet "CX" it should just populate either "Supplier Found" or "Supplier Not Found"
Currently it's not populating the last column with any data but the Macro isn't erroring at any point.
I've tried adding msgboxes and "Here" and "Here3" are being triggered but it doesn't seem to be hitting the section of code that is "Here2" so I think it's there that's causing the issue but not sure how to resolve it.
Screenshot of my Data is :CX Sheet
Fusion Sheet
Any help would be greatly appreciated.
Option Explicit
Sub CompareCXFusion()
Dim CX As Worksheet
Dim Fusion As Worksheet
Dim strTemp as string
Dim strCheck as string
Dim i As Long, J As Long
Dim CXArr As Variant
Dim FusionArr As Variant
Dim match As Boolean
Dim CXRng As Range
Dim FusionRng As Range
Set CX = ActiveWorkbook.Sheets("CX")
Set Fusion = ActiveWorkbook.Sheets("Fusion")
Set CXRng = CX.Range("A2", CX.Cells(Rows.Count, "A").End(xlUp).Offset(0, 6))
Set FusionRng = Fusion.Range("A2", Fusion.Cells(Rows.Count, "A").End(xlUp).Offset(0, 9))
CXArr = CXRng.Value2
FusionArr = FusionRng.Value2
strTemp = lcase(trim(FusionArr(J, 7)))
strCheck = lcase(trim(CXArr(i, 3)))
For i = 1 To UBound(CXArr)
Match = False
For J = 1 To UBound(FusionArr)
MsgBox "Here"
If (Instr(strTemp, strCheck) > 0) OR (InStr(strCheck, strTemp) > 0) Then
MsgBox"Here2"
CXArr(i, 6) = "Supplier Found"
Else
Msgbox"Here3"
CXArr(i, 6) = "Supplier not found"
End If
Next J
Next i
End Sub
The expected output i'd expect is: If in Column H of Fusion the Supplier Name is "Supplier A" and the value in Column D of sheet "CX" is "Supplier A LTD" then i'd expect it to populate column G in sheet CX with "Supplier Found" due to it being found in the string.
If you need any more info please let me know.
I don't know how to correctly insert examples of my data else I would have
Option Explicit
Sub CompareCXFusion()
Dim CX As Worksheet
Dim Fusion As Worksheet
Dim i As Long, J As Long, lastRowCX As Long, lastRowFU As Long
Dim CXText As String, FusionText As String
Dim match As Boolean
Dim CXRng As Range, FusionRng As Range
Set CX = ActiveWorkbook.Sheets("CX")
Set Fusion = ActiveWorkbook.Sheets("Fusion")
lastRowCX = CX.Range("D1").SpecialCells(xlCellTypeLastCell).Row - 1
lastRowFU = Fusion.Range("H1").SpecialCells(xlCellTypeLastCell).Row - 1
Set CXRng = CX.Range("D1:D" & lastRowCX)
Set FusionRng = Fusion.Range("H1:H" & lastRowFU)
For i = 1 To lastRowCX
match = False
For J = 1 To lastRowFU
'Debug.Print "Here"
FusionText = FusionRng.Range("A1").Offset(J, 0).Value
CXText = CXRng.Range("A1").Offset(i, 0).Value
If FusionText <> "" And CXText <> "" Then
If InStr(FusionText, CXText) Or InStr(CXText, FusionText) Then
'Debug.Print "Here2"
match = True
End If
End If
Next J
'Result goes to column G of CX range:
If match Then
CXRng.Range("A1").Offset(i, 3).Value = "Supplier found" ' "Supplier found - " & i & " - " & CXRng.Range("A1").Offset(i, 0).Address & " - " & CXRng.Range("A1").Offset(i, 3).Address
Else
CXRng.Range("A1").Offset(i, 3).Value = "Supplier NOT found" '"Supplier NOT found - " & i & " - " & CXRng.Range("A1").Offset(i, 0).Address & " - " & CXRng.Range("A1").Offset(i, 3).Address
End If
Next i
End Sub
You need to make sure to check for case sensitivity:
Dim strTemp as string
Dim strCheck as string
'Inside for I loop
'Inside for j Loop
strTemp = lcase(trim(FusionArr(J, 7)))
strCheck = lcase(trim(CXArr(i, 3)))
If (Instr(strTemp, strCheck) > 0) OR (InStr(strCheck, strTemp) > 0) Then
'...
End If
'end for j
'end for i
Hopefully the title is clear. I am trying to search through multiple tables on a single sheet. The information I am looking for is the same for all of the tables, just that the corresponding column is located in different spots (e.g. in one table the column I want to search is in I, while for another table it could be in O.) which makes it a bit more challenging for me.
I want to search through each column that has the same title (Load Number) and depending on its value, copy that entire row over to a sheet that corresponds with that value.
Below is what I have so far in VBA as well as a picture to hopefully clarify my issue.
Any help/advice is appreciated!
http://imgur.com/a/e9DyH
Sub Load_Number_Finder()
Dim ws As Worksheet
Dim i As Integer
Dim j As Integer
j = 1
Set ws = Sheets.Add(After:=Sheets("Master"))
ws.Name = ("Test Load " & j)
i = 1
Sheets("Master").Select
For Each cell In Sheets("Master").Range("M:M")
If cell.Value = "1" Then
j = 1
'Set WS = Sheets.Add(After:=Sheets("Master"))
'WS.Name = ("Test Load " & j)
matchRow = cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Copy
Sheets("Test Load " & j).Select
ActiveSheet.Rows(i).Select
ActiveSheet.Paste
Sheets("Master").Select
i = i + 1
ElseIf cell.Value = "" Then
' 2, 3, 4, 5, cases
Else
' Something needs to go here to catch when it doesnt have a load number on it yet
End If
' Err_Execute:
' MsgBox "An error occurred."
Next
End Sub
Try this function. This should work for you. Let me know what the results are with your sheet. I made a mock up sheet and tested it, it worked. I can make changes if this is not exactly what you are looking for.
Option Explicit
Sub copyPaste()
Dim rowCount, row_ix, temp, i As Integer
Dim TD_COL_IX As Integer
Dim td_value As String
Dim td_values() As String
rowCount = Worksheets("Master").Cells(Rows.Count, "A").End(xlUp).Row
For row_ix = 1 To rowCount
temp = isNewTable(CInt(row_ix))
If temp > 0 Then
TD_COL_IX = temp
ElseIf TD_COL_IX > 0 Then
td_value = Worksheets("Master").Cells(row_ix, TD_COL_IX)
If Not td_value = "" Then
td_values = Split(td_value, " ")
For i = 0 To UBound(td_values)
If Not sheetExists("Test Load " & td_values(i)) Then
Sheets.Add.Name = "Test Load " & td_values(i)
End If
If Worksheets("Test Load " & td_values(i)).Cells(1, 1).Value = "" Then
Worksheets("Master").Range(Worksheets("Master").Cells(row_ix, 1), Worksheets("Master").Cells(row_ix, TD_COL_IX - 1)).Copy _
Destination:=Worksheets("Test Load " & td_values(i)).Cells(1, 1)
Else
Dim rowCount_pasteSheet As Integer
rowCount_pasteSheet = Worksheets("Test Load " & td_values(i)).Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("Master").Range(Worksheets("Master").Cells(row_ix, 1), Worksheets("Master").Cells(row_ix, TD_COL_IX - 1)).Copy _
Destination:=Worksheets("Test Load " & td_values(i)).Cells(rowCount_pasteSheet + 1, 1)
End If
Next i
End If
End If
Next row_ix
End Sub
Function isNewTable(row_ix As Integer) As Integer
Dim colCount, col_ix As Integer
colCount = Worksheets("Master").Cells(row_ix, Columns.Count).End(xlToLeft).Column
For col_ix = 1 To colCount
If Not IsError(Worksheets("Master").Cells(row_ix, col_ix).Value) Then
If Worksheets("Master").Cells(row_ix, col_ix).Value = "LD #" Then
isNewTable = col_ix
Exit Function
End If
End If
Next col_ix
isNewTable = 0
End Function
' ####################################################
' sheetExists(sheetToFind As String) As Boolean
'
' Returns true if the sheet exists, False otherwise
' ####################################################
Public Function sheetExists(sheetToFind As String) As Boolean
Dim sheet As Worksheet
sheetExists = False
For Each sheet In Worksheets
If sheetToFind = sheet.Name Then
sheetExists = True
Exit Function
End If
Next sheet
End Function
I am trying to build a collection and take the Count of Unique Values from that Collection but am getting an error in building a Collection itself. Can anyone suggest me where I am going wrong. Kindly Share your thoughts. Please let me know how to find out the COUNT of UNIQUE VALUES as well.
Sub trial()
Dim sampleVisualBasicColl As Collection
For i = 2 To 10
Rng = Range("M" & i).value
StartsWith = Left(Rng, 3)
If StartsWith = "Joh" Then
sampleVisualBasicColl.Add Rng
Else
End If
Next
Debug.Print (sampleVisualBasicCol1)
End Sub
Using a collection you can just add Joh to the collection and then count the items:
'Using a collection
Sub Col_test()
Dim cCol As Collection
Dim i As Long
Set cCol = New Collection
On Error GoTo Err_Handler
With ThisWorkbook.Worksheets("Sheet1")
For i = 2 To 20
If Left(.Cells(i, 13), 3) = "Joh" Then
cCol.Add .Cells(i, 13).Value, .Cells(i, 13).Value
End If
Next i
End With
Debug.Print cCol.Count
On Error GoTo 0
Exit Sub
Err_Handler:
Select Case Err.Number
Case 457 'This key is already associated with an element of this collection
Err.Clear
Resume Next
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure Col_test."
Err.Clear
End Select
End Sub
If you want the count of each item (Joh, Ben... whatever else you have) then use a dictionary:
'Using a dictionary.
Sub Dic_Test()
Dim dict As Object
Dim i As Long
Dim sValue As String
Dim key As Variant
Set dict = CreateObject("Scripting.Dictionary")
With ThisWorkbook.Worksheets("Sheet1")
For i = 2 To 20
If Len(.Cells(i, 13)) >= 3 Then
sValue = Left(.Cells(i, 13), 3)
If dict.exists(sValue) Then
dict(sValue) = dict(sValue) + 1
Else
dict(sValue) = 1
End If
End If
Next i
End With
For Each key In dict.keys
Debug.Print key & " = " & dict(key)
Next key
End Sub
Note: I'm using Cells within the code rather than Range. Cells(2,13) is M2 (13th column, 2nd row).
I find this link very helpful with dictionaries: https://excelmacromastery.com/vba-dictionary/
As a further update (after answer accepted) and using the lists you gave in your question here: Excel VBA - Formula Counting Unique Value error this code with dictionaries will return Joh = 4, Ian = 3
'Using a dictionary.
Sub Dic_Test()
Dim dict As Object
Dim dictFinal As Object
Dim i As Long
Dim sValue As String
Dim key As Variant
Dim keyFinal As String
Set dict = CreateObject("Scripting.Dictionary")
Set dictFinal = CreateObject("Scripting.Dictionary")
'Get the unique values from the worksheet.
With ThisWorkbook.Worksheets("Sheet1")
For i = 2 To 20
If Len(.Cells(i, 13)) >= 3 Then
sValue = .Cells(i, 13).Value
If dict.exists(sValue) Then
dict(sValue) = dict(sValue) + 1
Else
dict(sValue) = 1
End If
End If
Next i
End With
'Count the unique values in dict.
For Each key In dict.keys
keyFinal = Left(key, 3)
If dictFinal.exists(keyFinal) Then
dictFinal(keyFinal) = dictFinal(keyFinal) + 1
Else
dictFinal(keyFinal) = 1
End If
Next key
For Each key In dictFinal.keys
Debug.Print key & " = " & dictFinal(key)
Next key
End Sub
You need to create the collection as well as declaring it.
Sub trial()
Dim myCol As Collection
Set myCol= New Collection ' creates the collection
For i = 2 To 10
Rng = Range("M" & i).value
StartsWith = Left(Rng, 3)
If StartsWith = "Joh" Then
myCol.Add Rng
Else
End If
Next
For each x in myCol
Debug.Print x
Next x
End Sub
Hey this code will help u since it's collecting Unique values in Listbox,,
Private Sub UserForm_Initialize()
Dim cUnique As Collection
Dim Rng As Range
Dim Cell As Range
Dim sh As Worksheet
Dim vNum As Variant
Set sh = ThisWorkbook.Sheets("Sheet1")
Set Rng = sh.Range("A2", sh.Range("A2").Value ="John". End(xlDown))
Set cUnique = New Collection
On Error Resume Next
For Each Cell In Rng.Cells
cUnique.Add Cell.Value, CStr(Cell.Value)
Next Cell
On Error GoTo 0
For Each vNum In cUnique
Me.ListBox1.AddItem vNum
Next vNum
End Sub
You have not declared Variable Rng & i these are the most important thing to do. Meanwhile I would like to suggest this Formula,,
=Sum(if(Frequency (if(Len(B2 :B20) >0,Match(B2 :B20, B2 :B20, 0),""),if(Len(B2 :B20) >Match(B2 :B20, B2 :B20, 0),"",))>0,1))
Its Array formula so finish with Ctrl +shift +enter.
You can use this one also,
Sub CountUnique()Dim i, count, j As Integer count = 1 For i = 1 To 470 flag = False If count
1 Then For j = 1 To count If Sheet1.Cells(i,
3).Value = Sheet1.Cells(j, 11).Value Then flag
= True End If Next j Else flag = False End If If flag = False Then Sheet1.Cells(count,
11 ).Value = Sheet1.Cells(i, 3).Value count = count + 1 End IfNext i Sheet1.Cells( 1 ,
15 ).Value = count End Sub