I am new in VBA and I am trying to solve one problem. I have Only Items column in Excel data like below. And I want to add code for each item which is in Code column.
Code Items
Animals:
AN Cow
AN Dog
AN Zeebra
AN Deer
Flower:
FL Rose
FL Sunflower
Fruit:
FR Mango
FR Banana
FR Pineapple
FR Cherry
I used following Loop for that
For Each Cell In Sheets("Sheet1").Range("B" & Sheets("Sheet1").Columns("B:B").Cells.Find(what:="Animal:", searchdirection:=xlPrevious).Offset(1, 0).Row & ":B" & Sheets("Sheet1").Range("B").End(xlDown).Row)
If Cell.Value <> "Flower:" Then
Cell.Offset(1, 0).Select
Cell.Offset(0, -1).Value = "AN"
ElseIf Cell.Value = "Flower:" Then
Range(Selection, Selection.End(xlDown)).Select
Cell.Offset(0, -1).Value = "FL"
End If
Next Cell
But, this is not acheiving what I need. can please someone let me know what to do in this case?
This code uses a different approach (do while) but achieves what you want. It identifies the category by looking for a colon : within the cell. It then sets the code and applies it to the offset(0,-1) until a new code is found.
Sub FillOffset()
Dim ws As Worksheet
Set ws = Sheets("Sheet1")
Dim i As Long
i = 2
Dim cell As Range
Do Until i > ws.Range("B" & Rows.Count).End(xlUp).Row
If InStr(1, ws.Range("B" & i).Text, ":", vbTextCompare) Then
Dim code As String
code = UCase(Left(ws.Range("B" & i).Text, 2))
Else
ws.Range("B" & i).Offset(0, -1) = code
End If
i = i + 1
Loop
End Sub
Sample output:
#mehow beat me by a a few seconds, but this code will also solve your problem.
Sub AddCodeForItems()
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
Dim lastRow As Long
Dim code As String
Set ws = ThisWorkbook.ActiveSheet
lastRow = ws.Range("B" & ws.Rows.Count).End(xlUp).Row
Set rng = ws.Range("B2:B" & lastRow)
For Each cell In rng
If Right(Trim(cell.Value), 1) = ":" Then
code = UCase(Left(Trim(cell.Value), 2))
Else
cell.Offset(, -1).Value = code
End If
Next cell
End Sub
Slightly different approach:
Sub tgr()
Dim rngFound As Range
Dim rngLast As Range
Dim strFirst As String
With ActiveSheet.Columns("B")
Set rngFound = .Find(":", .Cells(.Cells.Count), xlValues, xlPart)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
Set rngLast = Range(rngFound.Offset(1), .Cells(.Cells.Count)).Find(":", , xlValues, xlPart)
If rngLast Is Nothing Then Set rngLast = .Cells(.Cells.Count).End(xlUp).Offset(1)
Range(rngFound.Offset(1, -1), rngLast.Offset(-1, -1)).Value = UCase(Left(rngFound.Text, 2))
Set rngFound = Columns("B").Find(":", rngFound, xlValues, xlPart)
Loop While rngFound.Address <> strFirst
End If
End With
Set rngFound = Nothing
Set rngLast = Nothing
End Sub
Related
I am trying to insert a blank row above a row that contains a specific word. But so far I can only insert it below this row.
Sub INSERTROW()
Dim c As Range
Dim lRow As Long
lRow = 1
Dim lRowLast As Long
Dim bFound As Boolean
With ActiveSheet
lRowLast = .Cells(.Rows.Count, 1).End(xlUp).Row
Do
Set c = .Range("A" & lRow)
If c.Value Like "*SEARCHED VALUE*" Then
bFound = True
ElseIf bFound Then
bFound = False
If c.Value <> "BLANKROW" Then
c.EntireRow.Insert
lRowLast = lRowLast + 1
c.Offset(-1, 0).Value = "BLANKROW"
c.Offset(-1, 0).Font.Color = RGB(0, 0, 0)
End If
End If
lRow = lRow + 1
Loop While lRow <= lRowLast + 1
End With
End Sub
It's easier and faster (AFAIK) if you use the find method.
See that I insert the row where the value is found and then I refer to the previous row with the offset function.
Finally, as a good practice, try to name your procedures and variables to something meaningful and indent your code (you may use www.rubberduckvba.com)
Public Sub InsertRowBeforeWord()
Dim findString As String
findString = "*SEARCHED VALUE*"
Dim lastRow As Long
lastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 1).End(xlUp).Row
Dim searchRange As Range
Set searchRange = ActiveSheet.Range("A1:A" & lastRow)
Dim returnRange As Range
Set returnRange = searchRange.Find(What:=findString, _
After:=searchRange.Cells(searchRange.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not returnRange Is Nothing Then
returnRange.Offset(0, 0).EntireRow.Insert
returnRange.Offset(-1, 0).Value = "BLANKROW"
returnRange.Offset(-1, 0).Font.Color = RGB(0, 0, 0)
End If
End Sub
Let me know if it works.
I am a beginner to VBA. On sheet one I have data formatted like this:
SHEET 1
What I want to do is use VBA to spit out the following graph which dynamically populates the region depending on how many it finds:
SHEET 2
This is my first bit of VBA so I am struggling a bit. This is my idea of how to approach this problem:
My idea was to scroll down the string in my data in sheet1 col A and determine if it's a date we have seen before or not:
Public Sub Test()
ActiveSheet.Range("Sheet1!A1:A5000").AdvancedFilter Action:=xlFilterCopy, CopyToRange.Range("Sheet2!A1"), Unique:=True
End Sub
Questions
Is this flow diagram taking the right approach?
If so, how do I implement this kind of "Is this unique, if so do this, if not do this" kind of setup.
How can I start this code so I have something to build on?
This is what I have so far:
https://gist.githubusercontent.com/employ/af67485b8acddce419a2/raw/6dda3bb1841517731867baec56a0bf2ecf7733a7/gistfile1.txt
For different approach please see below:
Sheet 1 layout (Source):
Sheet 2 Layout (Target):
Sub SalesRegion()
Dim ws1, ws2 As Worksheet
Dim wb As Workbook
Dim ws1LastRow, ws2LastRow, salesVal As Long
Dim destFind, dateFind As Range
Dim destStr As String
Dim dateStr As Date
Dim targetCol, targetRow As Long
Set wb = ActiveWorkbook '<- Your workbook
Set ws1 = wb.Sheets("Sheet1") '<- Your source worksheet
Set ws2 = wb.Sheets("Sheet2") '<- Your destination worksheet
ws1LastRow = ws1.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To ws1LastRow
destStr = ws1.Range("C" & i).Value
dateStr = ws1.Range("A" & i).Value
salesVal = ws1.Range("B" & i).Value
With ws2.Rows("1:1") '<- row on destination sheet which contains countries
Set destFind = .Find(What:=destStr, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not destFind Is Nothing Then
targetCol = destFind.Column
With ws2.Columns("A:A") '<- Column on destination sheet which contains months
'You may need to adjust date format below depending on your regional settings
Set dateFind = .Find(What:=Format(ws1.Range("A" & i).Value, "MMM-yy"), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not dateFind Is Nothing Then
targetRow = dateFind.Row
ws2.Cells(targetRow, targetCol).Value = ws2.Cells(targetRow, targetCol).Value + salesVal
Else
ws2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = dateStr
targetRow = ws2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Row
ws2.Cells(targetRow, targetCol).Value = salesVal
End If
End With
Else
ws2.Cells(1, Columns.Count).End(xlToLeft).Offset(0, 1).Value = destStr
targetCol = ws2.Cells(1, Columns.Count).End(xlToLeft).Column
With ws2.Columns("A:A") '<- Column on destination sheet which contains months
'You may need to adjust date format below depending on your regional settings
Set dateFind = .Find(What:=Format(ws1.Range("A" & i).Value, "MMM-yy"), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not dateFind Is Nothing Then
targetRow = dateFind.Row
ws2.Cells(targetRow, targetCol).Value = ws2.Cells(targetRow, targetCol).Value + salesVal
Else
ws2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = dateStr
targetRow = ws2.Range("A" & Rows.Count).End(xlUp).Row
ws2.Cells(targetRow, targetCol).Value = salesVal
End If
End With
End If
End With
Next
End Sub
First, I agree with the others that you should look for a solution using the built-in capabilities of the Pivot Table.
Since you've mentioned that it does not meet your expectations, I threw together some code that works to summarize the data as you've requested. Let me know if it does the trick, if you need any added help adjusting it for your needs, or if you have any other general questions.
Sub SummarizeInNewSheet()
Dim wsOrigin As Worksheet
Dim wsDest As Worksheet
Dim rngOrigin As Range
Dim oDict As Object
Dim cel As Range
Dim rngLocations As Range
Dim nLastRow As Long
Dim nLastCol As Long
Dim rngInterior As Range
Dim rngAllDates As Range
Dim rngAllLocations As Range
Dim rngAllSales As Range
Application.ScreenUpdating = False
Set wsOrigin = Worksheets("Sheet1")
Set wsDest = Worksheets("Sheet2")
Set rngOrigin = wsOrigin.Range("A1").CurrentRegion
Intersect(rngOrigin, wsOrigin.Columns(1)).Copy wsDest.Range("A1")
wsDest.Range(wsDest.Range("A1"), wsDest.Range("A1").End(xlDown)).RemoveDuplicates Columns:=1, Header:=xlYes
Set oDict = CreateObject("Scripting.Dictionary")
Set rngLocations = wsDest.Range("B1")
For Each cel In Intersect(rngOrigin, wsOrigin.Columns(3))
If cel.Row = 1 Then
Else
If oDict.exists(cel.Value) Then
'Do nothing for now
Else
oDict.Add cel.Value, 0
rngLocations.Value = cel.Value
Set rngLocations = rngLocations.Offset(, 1)
End If
End If
Next cel
nLastRow = wsDest.Cells(Rows.Count, 1).End(xlUp).Row
nLastCol = wsDest.Cells(1, Columns.Count).End(xlToLeft).Column
Set rngInterior = wsDest.Range(wsDest.Range("B2"), wsDest.Cells(nLastRow, nLastCol))
Set rngAllDates = wsOrigin.Range(wsOrigin.Range("A2"), wsOrigin.Range("A2").End(xlDown))
Set rngAllSales = wsOrigin.Range(wsOrigin.Range("B2"), wsOrigin.Range("B2").End(xlDown))
Set rngAllLocations = wsOrigin.Range(wsOrigin.Range("C2"), wsOrigin.Range("C2").End(xlDown))
For Each cel In rngInterior
cel.Value = Application.WorksheetFunction.SumIfs(rngAllSales, rngAllDates, wsDest.Cells(cel.Row, 1), rngAllLocations, wsDest.Cells(1, cel.Column))
Next cel
Application.ScreenUpdating = True
End Sub
I need help modifying this code to match First and Last names across 2 worksheets, then remove matches from the Sub sheet. At the moment it only matches 2 columns across 1 sheet. Specifics:
How do i change this code so Names on 'Sheet 1' Column 'B' are Matched to names on 'sheet 2' column 'E' & all matches are deleted from 'Sheet 1". Same is repeated for 'Sheet 1' Column 'C' to 'Sheet 2' Column 'F'.
Sub CompareNames()
Dim rngDel As Range
Dim rngFound As Range
Dim varWord As Variant
Dim strFirst As String
With Sheets("ADULT Sign On Sheet")
For Each varWord In Application.Transpose(.Range("A1", .Cells(.Rows.Count,"A").End(xlUp)).Value)
If Len(varWord) > 0 Then
Set rngFound = .Columns("B").Find(varWord, .Cells(.Rows.Count, "B"), xlValues, xlPart)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
If Not rngDel Is Nothing Then Set rngDel = Union(rngDel, rngFound) Else Set rngDel = rngFound
Set rngFound = .Columns("B").Find(varWord, rngFound, xlValues, xlPart)
Loop While rngFound.Address <> strFirst
End If
End If
Next varWord
End With
If Not rngDel Is Nothing Then rngDel.Delete
Set rngDel = Nothing
Set rngFound = Nothing
End Sub
Loops through all values in Sheet1 Column B. If that value is found in Sheet2 Column E, the entire row in Sheet1 is deleted. Then it loops through all values in Sheet1 Column C. If that value is found in Sheet2 Column F, the entire row in Sheet1 is deleted.
Sub DeleteCopy()
Dim LastRow As Long
Dim CurRow As Long
Dim DestLast As Long
LastRow = Sheets("Sheet1").Range("B" & Rows.Count).End(xlUp).Row
DestLast = Sheets("Sheet2").Range("E" & Rows.Count).End(xlUp).Row
For CurRow = 2 To LastRow 'Assumes your first row of data is in row 2
If Not Sheets("Sheet2").Range("E2:E" & DestLast).Find(Sheets("Sheet1").Range("B" & CurRow).Value, LookIn:=xlValues, LookAt:=xlWhole) Is Nothing Then
Sheets("Sheet1").Range("B" & CurRow).Value = ""
Else
End If
Next CurRow
LastRow = Sheets("Sheet1").Range("C" & Rows.Count).End(xlUp).Row
DestLast = Sheets("Sheet2").Range("F" & Rows.Count).End(xlUp).Row
For CurRow = 2 To LastRow 'Assumes your first row of data is in row 2
If Not Sheets("Sheet2").Range("F2:F" & DestLast).Find(Sheets("Sheet1").Range("C" & CurRow).Value, LookIn:=xlValues, LookAt:=xlWhole) Is Nothing Then
Sheets("Sheet1").Range("C" & CurRow).Value = ""
Else
End If
Next CurRow
End Sub
Try this, you will have to call it twice once with the first criteria and then again with the second critiera
I think I have it set up properly for the first criteria
Sub DeleteIfMatchFound()
Dim SearchValues As Variant
Dim wsSource As Worksheet, wsTarget As Worksheet
Dim sLR As Long, tLR As Long, i As Long
Set wsSource = ThisWorkbook.Worksheets("Sheet1")
Set wsTarget = ThisWorkbook.Worksheets("Sheet2")
sLR = wsSource.Range("B" & wsSource.Rows.Count).End(xlUp).Row
tLR = wsTarget.Range("E" & wsSource.Rows.Count).End(xlUp).Row
SearchValues = wsSource.Range("B2:B" & sLR).Value
For i = 1 To (tLR - 1)
If Not IsError(Application.match(SearchValues(i, 1), wsTarget.Range("E2:E" & tLR), 0)) Then
wsTarget.Rows(i + 1).Delete
End If
Next i
End Sub
In excel 2010, how to do a validation if cell contain ',' then pop up a message to user ?
Please try to show your work ..
lets say Column A contains the data then below code work perfectly
this is what u wanted (TESTED)
Sub tested()
Dim erange As Range
Dim lrow As Integer
lrow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For Each erange In Range("A2:A" & lrow)
If InStr(erange.Value, ",") > 0 Then
MsgBox (erange.Address & " contains Comma ")
erange.Interior.Color = vbRed
End If
Next erange
End Sub
Using normal data validation, you could try this
=(LEN(A1) = LEN(SUBSTITUTE(A1,",","")))
If you want to avoid unnecessary loop use below code.
Sub findComma()
Dim srcRng As Range, findRng As Range
Dim firstCell As String
Dim lrow As Integer
lrow = Range("A" & Rows.Count).End(xlUp).Row
Set srcRng = Range("A1:A" & lrow)
Set findRng = srcRng.Find(What:=",", LookIn:=xlValues, LookAt:=xlPart)
If Not findRng Is Nothing Then firstCell = findRng.Address
Do Until findRng Is Nothing
MsgBox (findRng.Address & " contains Comma ")
findRng.Interior.Color = vbRed
Set findRng = srcRng.FindNext(findRng)
If findRng.Address = firstCell Then Exit Sub
Loop
End Sub
The workbook contains three sheets:
Item-style (contains in colA the item no., colB the style of the item)
Style (List of styles we want)
Style template (List of items within the styles specified in the cols)
I need a macro that does three things:
Copy the list of styles from the Style sheet and paste & transpose in Style template starting from row 2. Row 1 of all columns needs to be left blank.
The macro needs to select each style in style template one by one, which is now in different columns. These will be the search criteria.
On the basis of style selected in step 2, the macro needs to do a search in item-style sheet and select all the items that have the selected style and paste all these items beneath the corresponding style in style-template sheet. If there are no items corresponding to the selected style, then it should mention "No items" beneath the corresponding style.
Here's a link to the workbook for easy understanding
StyleProject
Though the workbook mentions only three styles the macro should have the capability of working with more than 50 styles.
Here's the code I have:
Sub StyleProject()
Application.ScreenUpdating = False
Dim ws As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Set ws = Sheets("Item-Style")
Set ws2 = Sheets("Style")
Set ws3 = Sheets("Style Template")
Dim rng As Range, secRng As Range
Dim i, j, k
Sheets("Style Template").Activate
finalcol = Cells(2, 50).End(x1toleft).Column
For i = 2 To finalcol
j = Cells(2, i).Value
lr = ws.Range("A" & Rows.Count).End(xlUp).Row
For k = 2 To lr
Set rng = ws.Range("B" & i)
If StrComp(CStr(rng.Text), j, 1) = 0 Then
ws.Rows(k & ":" & k).Copy
nxtRow = ws3.Range(i & Rows.Count).End(xlUp).Row + 1
ws2.Rows(nxtRow & ":" & nxtRow).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Set rng = Nothing
End If
Next k
Next i
Application.ScreenUpdating = True
End Sub
It ends up in error trying to figure out nextrng I believe.
Sub StyleProject()
Dim wsStyle As Worksheet
Dim wsData As Worksheet
Dim wsTemplate As Worksheet
Dim StyleCell As Range
Dim rngFound As Range
Dim arrResults() As Variant
Dim strFirst As String
Dim ResultIndex As Long
Dim StyleIndex As Long
Set wsStyle = Sheets("Style")
Set wsData = Sheets("Item Data")
Set wsTemplate = Sheets("Style Template")
With wsStyle.Range("A2", wsStyle.Cells(Rows.Count, "A").End(xlUp))
If .Row < 2 Then Exit Sub 'No data
ReDim arrResults(1 To 1 + Evaluate("MAX(COUNTIF(" & wsData.Columns("B").Address(External:=True) & "," & .Address(External:=True) & "))"), 1 To .Cells.Count)
For Each StyleCell In .Cells
StyleIndex = StyleIndex + 1
ResultIndex = 1
arrResults(ResultIndex, StyleIndex) = StyleCell.Text
Set rngFound = wsData.Columns("B").Find(StyleCell.Text, wsData.Cells(Rows.Count, "B"), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
ResultIndex = ResultIndex + 1
arrResults(ResultIndex, StyleIndex) = wsData.Cells(rngFound.Row, "A").Text
Set rngFound = wsData.Columns("B").Find(StyleCell.Text, rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
Next StyleCell
End With
If UBound(arrResults, 1) > 1 Then
wsTemplate.Range("B2", wsTemplate.Cells(Rows.Count, Columns.Count)).Clear
wsTemplate.Range("B2").Resize(UBound(arrResults, 1), UBound(arrResults, 2)).Value = arrResults
With wsTemplate.Range("B2").Resize(, UBound(arrResults, 2))
.Font.Bold = True
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.EntireColumn.AutoFit
End With
End If
Set wsStyle = Nothing
Set wsData = Nothing
Set wsTemplate = Nothing
Set StyleCell = Nothing
Set rngFound = Nothing
Erase arrResults
End Sub