I know almost nothing about VBA and need some help! I've recorded a simple macro that will insert a row and perform some relative cut/paste when a certain value ("Choice") is found in column B. I would like this macro to loop until it reaches the end of the data set (keep in mind part of the macro inserts more rows as it goes). I've gotten it to loop and do what I want, but I can't figure out how to make it stop and not be infinite. Searching for blanks will not help as there are several blanks within the data set. Hoping for a helpful Do Until code? If you have a solution, can you please append it to my macro in your reply so I can see how the whole thing would look? Thank You!!
Sub Macro6()
'
' Macro6 Macro
' Spacer
'
' Keyboard Shortcut: Ctrl+q
'
Dim c As Range
For Each c In Range("B1:B3000")
Cells.Find(What:="choice", After:=ActiveCell, LookIn:=xlFormulas, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
ActiveCell.Rows("1:1").EntireRow.Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
ActiveCell.Offset(1, 0).Range("A1:B1").Select
Selection.Cut
ActiveCell.Offset(-1, 0).Range("A1").Select
ActiveSheet.Paste
ActiveCell.Offset(1, 0).Range("A1").Select
Next
End Sub
Sub Macro6()
'
' Macro6 Macro
' Spacer
'
' Keyboard Shortcut: Ctrl+q
'
Dim c As Range
Dim lastRow As Long
With ActiveSheet
lastRow = .Cells(.Rows.count, "B").End(xlUp).Row
For I = lastRow To 1 Step -1
Debug.Print .Cells(I, 2).Value
If InStr(1, .Cells(I, 2).Value, "choice") > 0 Then
.Cells(I, 2).Rows("1:1").EntireRow.Select
Selection.Insert Shift:=xlDown
ActiveCell.Offset(1, 0).Range("A1:B1").Select
Selection.Cut
ActiveCell.Offset(-1, 0).Range("A1").Select
ActiveSheet.Paste
ActiveCell.Offset(1, 0).Range("A1").Select
End If
Next
End With
End Sub
When I run this code against this input ...
I get this output ...
Is this the result you were looking for? If not, can you provide a better description of the result you need?
Related
New to forum and vba but want to learn more.
Got two tables of large data and want to look for a cell value equal to the cell value to the left of my active cell in table 1 and then find that value in the 2nd table. When value is found I want to return the cell value found in the 5th column to the right of column A in the 2nd table.
The macro I have created works well - if it hadn't been that it always looks for the same value "10.136.32.10" i.e. this value does not change as the active cell moves down table 1. I would like the value to change depending on what is actually copied from the cell to the left. Is there a way to do this? I use Ctrl+f function and then paste in the cell value copied from table 1
Have the following macro:
Sub Makro2()
'
' Makro2 Makro
'
'
ActiveCell.Offset(0, -1).Range("A1").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("SKF-NOV-6-2017").Select
Cells.Find(What:="10.136.32.10", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
Selection.End(xlToLeft).Select
ActiveCell.Offset(0, 4).Range("A1").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("All Equipment").Select
ActiveCell.Offset(0, 1).Range("A1").Select
ActiveSheet.Paste
ActiveCell.Offset(1, 0).Range("A1").Select
End Sub
Here is the code by which you can do your job. This macro searches immediately on all rows. If you only need to search for an active cell, then you need to remove the loop.
Sub macro2()
Dim lr As Long, r As Long, c As Long
Dim str As String
lr = Cells(Rows.Count, 1).End(xlUp).Row
For r = 1 To lr
str = Cells(r, c).Offset(0, -1)
Sheets("SKF-NOV-6-2017").Select
Cells.Find(What:=str, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
Selection.End(xlToLeft).Select
ActiveCell.Offset(0, 4).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("All Equipment").Select
Cells(r, c + 1).past
Next r
End Sub
firstly, I'm having error running the code from Excel workbook directly. It leads to the error message mentioned below
We looked at all the data next to your selection and didn't see a pattern for filling in values for you. To use Flash Fill, enter a couple of examples of the output you'd like to see, keep the active cell in the column you want filled in and click the Flash Fill button again
However, I could run the code if is played from VBA windows under the developers tab. But Is limited to only 1 run before an error message 1004 pops up and also code error when played again.
Please help. Never taught or learnt VBA in ever. Code below is a mash up of researched on the net and trial & error.
Sub Graph()
'
' Graph Macro
'
' Keyboard Shortcut: Ctrl+e
'
'Select values in a column from specified workbook and sheet
Dim LR As Long, cell As Range, rng As Range
Windows("Area3-LG").Activate
With Sheets("Graph data")
LR = .Range("B" & Rows.Count).End(xlUp).Row
For Each cell In .Range("B4:B" & LR)
If cell.Value <> "" Then
If rng Is Nothing Then
Set rng = cell
Else
Set rng = Union(rng, cell)
End If
End If
Next cell
'Error with rng.select when Macro is runned again
rng.Select
End With
Selection.Copy
'Open next workbook
Windows("InstData_TEMS_Existing").Activate
'Open Sheet L
Sheets("L").Select
'Select empty field fromn column AA
Range("AA" & Rows.Count).End(xlUp).Offset(1).Select
'paste selection to empty field
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'Go back to previous workbook & delete column
Windows("Area3-LG").Activate
Sheets("Graph data").Select
Columns("B:B").Select
Application.CutCopyMode = False
Selection.Delete Shift:=xlToLeft
Sheets("Graph Data").Select
End Sub
Thanks in advance (:
Try the code below, without all the unnecessary Select, Activate, and Selection:
Sub Graph()
'
' Graph Macro
'
' Keyboard Shortcut: Ctrl+e
'
'Select values in a column from specified workbook and sheet
Dim LR As Long, cell As Range, rng As Range
With Workbooks("Area3-LG").Sheets("Graph data")
LR = .Range("B" & .Rows.Count).End(xlUp).Row
For Each cell In .Range("B4:B" & LR)
If cell.Value <> "" Then
If rng Is Nothing Then
Set rng = cell
Else
Set rng = Union(rng, cell)
End If
End If
Next cell
End With
rng.Copy ' copy the union range (no need to select it first)
' paste without all the selecting
With Windows("InstData_TEMS_Existing").Sheets("L")
' Paste (without select) un the next empty cell fromn column AA
.Range("AA" & .Rows.Count).End(xlUp).Offset(1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
End With
Application.CutCopyMode = False
'Go back to previous workbook & delete column
Workbooks("Area3-LG").Sheets("Graph data").Columns("B:B").Delete Shift:=xlToLeft
End Sub
obviously I'm really new to VBA- this my first Macro (and I had a blast making it), but it runs really poorly and crashes every time. Do you have any tips on how I can make it run more efficiently?
PS - I need to do the special paste/ find replace (£) because of a stange bug where blank cells (that had formulas) get pasted as non-blanks in the operation
Sub DTC_Generator()
Application.EnableEvents = False 'Prevents screen from moving through cells/events'
Application.ScreenUpdating = False 'Prevents screen from tabbing'
Application.CutCopyMode = False 'prevents gray residue after copy/paste'
Application.DisplayStatusBar = False
'LOOP RANGE
Dim A As Integer
Lstrow = Sheet4.Range("A" & Rows.Count).End(xlUp).Row
For A = 2 To Lstrow
Sheet4.Activate
Range("A2").End(xlDown).Select
Lstrow = ActiveCell.Row
Cells(A, 1).Copy
Range("L1").Activate
ActiveCell.PasteSpecial Paste:=xlPasteValues
'BEGIN MACRO
'PASTE PRE-GENERATOR ATTRIBUTES
Sheet4.Activate
Range("AA2:AL36").Delete
Range("M2:X36").Copy
Range("AA2:AL36").PasteSpecial Paste:=xlPasteValues
Range("AA2:AL36").Copy
Sheet7.Activate
Range("A2").PasteSpecial Paste:=xlPasteValues
Range("A2:AL36").Select
Selection.Replace What:="", Replacement:="£", LookAt:=xlWhole, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Range("A2:AL36").Select
Selection.Replace What:="£", Replacement:="", LookAt:=xlWhole, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
'DElETE OLD DATA
'SELECT ATTRIBUTE DATA
Sheet7.Activate
Range("M2").Select
'Loops through unique values until "no"
Do Until ActiveCell = "No"
ActiveCell.Offset(1, 0).Select
Loop
'bumps it back 1 row and over 19 columns'
ActiveCell.Offset(-1, 19).Select
ActiveCell.Name = "Bottom_Left"
Range("BH2:Bottom_Left").Copy
'PASTE INTO ATTRIBUTE INPUT FILE'
Sheet2.Activate
Range("A:A").End(xlDown).Offset(1, 0).Select
Lastrow = ActiveCell.Row
Cells(Lastrow, 1).PasteSpecial Paste:=xlPasteValues
Next A
MsgBox ("success?")
End Sub
I can't be sure but I am guessing that the following could be a quick fix to your "crashing" problem.
Change:
Do Until ActiveCell = "No"
ActiveCell.Offset(1, 0).Select
Loop
to
Do Until ActiveCell.Value2 = "No" or ActiveCell.Value2 = vbNullString
ActiveCell.Offset(1, 0).Select
Loop
Actually I have to thank you for this post as this is a prime-case why one should always try to avoid Do ... Loop (if at all possible). These kind of loops go on forever and have a tendency to crash Excel whenever the "exit point" in the until clause is poorly selected. In this case you are saying that it should keep on going until the value of the ActiveCell is No. Yet, you are forgetting that the next available cell might not contain No but nothing instead. So, if this loop goes beyond your data grid (UsedRange) then it will keep on looking for No even in row 1,048,576 and beyond. This can easily crash your Excel.
Looks like you're asking it to do the same thing over and over again. When you write 'for a = 2 to lastrow' that means it's going to everything between that and 'next a', in this instance, 36 times. Did you mean to do that? One of the things it does 36 times is an infinite loop: 'do until active cell' just selects a cell, it looks like everything you want it to do is below 'loop' which means it will not do it to each active cell, plus, if it does not find 'active cell = no' it will never end (infinite loop) and crash you.
I took a guess as to what you're trying to accomplish but got lost after the loop. I've written some code to get you started and comments to help you out. Let me know what you're trying to do in the loop and I'll try to help.
Sub DTC_Generator()
Application.EnableEvents = False 'Prevents screen from moving through cells/events'
Application.ScreenUpdating = False 'Prevents screen from tabbing'
Application.CutCopyMode = False 'prevents gray residue after copy/paste'
Application.DisplayStatusBar = False
Sheet4.Name = "DTC_Generator" 'by naming the sheet you can work 'with' it,
'thereby making the code specific to this workbook so if you have other workbooks open it will not get confused
'about which workbook it's processing
'avoid selecting and activating if at all possible, saves time/cpu resources
Dim A As Long 'integer is limited in its length, just go ahead and always use Long for numbers
Dim Lastrow1 As Long
Dim Lastrow2 As Long
Dim Lastrow As Long
Dim x As Variant
With ThisWorkbook
With .Sheets("DTC_Generator")
'seems like the data you want to use is in columns M:X so goon base last row on those
Lastrow1 = .Range("M" & Rows.Count).End(xlUp)
Lastrow2 = .Range("X" & Rows.Count).End(xlUp)
If Lastrow2 > Lastrow1 Then Lastrow = Lastrow2 Else Lastrow = Lastrow1
.Cells.ClearFormats 'remove if you need to keep formats
.Cells.Copy 'get more specific if you need to keep formulas
.Range("A1").PasteSpecial xlPasteValues
.Columns("A").Value = .Columns("A").Value 'this does the whole column at once, no need to loop through each cell
.Range("L1").Value = .Range("A2").Value 'you were doing this for each cell in column A, doesn't seem right so I moved it here but you can move it if you need to
'you were also recalculating your lastrow for every cell in A
.Range("M2:X" & Lastrow).Copy
.Range("AA2").PasteSpecial xlPasteValues
Application.CutCopyMode = False
'you don't need to move it to a separate sheet to clean it up
'you may not need to do this at all, uncomment if you do
'.Columns("AA:AAL").Replace What:="", Replacement:="£", LookAt:=xlWhole, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
'.Columns("AA:AAL").Replace What:="£", Replacement:="", LookAt:=xlWhole, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False
'this is better than a loop cuz it will def just do the range so an infinite loop won't happen and crash you
'i think your "Do Until ActiveCell = "No"" was meant to loop through M2:X36, if so, do this
For Each x In Range(.Range("M2"), .Range("M" & Rows.Count).End(xlUp))
'***************************************************
'YOU LOST ME AFTER THIS - WHAT ARE YOU TRYING TO DO?
'***************************************************
Next x
End With
End With
'be sure to turn stuff back on
Application.EnableEvents = True
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
MsgBox "success?"
End Sub
I am trying to transpose every second and third row to columns B and C and then preferably delete the old rows so that I don't have two unused rows in B and C. I tried recording a macro, which worked for only the selection I made. Then I tried deleting the specific selections and replacing them with an offset range but I keep getting an error in the PasteSpecial line.
Sub SortRawData()
'
' SortRawData Macro
'
' Keyboard Shortcut: Ctrl+q
'
Selection.Offset(1, 0).Resize(Selection.Rows.Count + 2, _
Selection.Columns.Count).Select
ActiveCell.Copy
ActiveCell.Offset(-1, 1).Select
ActiveCell.PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
End Sub
I tried initially using Selection everywhere I have ActiveCell but neither seemed to work. I know I am missing the selection for the two rows I want to delete after I transpose the data into column B and C. What I have is a raw data dump of information that is formatted as:
Item1 Weight1 Color1 Item2 Weight2 Color2 Item 3 Weight 3 Color 3
I can get it to transpose one selection at a time by I can't seem to square away the automation of it.
Sub SortRawData2()
'
' SortRawData2 Macro
'
' Keyboard Shortcut: Ctrl+w
'
Selection.Copy
Range("B1").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Rows("2:3").Select
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
End Sub
This is the initial recorded macro and even it fails debugging at the PasteSpecial line. Any suggestions would be much appreciated!
Thanks!
Try this, then code an autofilter to remove the empty rows:
Sub SortRawData2()
Dim lLastRow As Long, lLoop As Long
lLastRow = Cells(Rows.Count, 1).End(xlUp).Row
For lLoop = 1 To lLastRow Step 3
Cells(lLoop, 2) = Cells(lLoop + 1, 1)
Cells(lLoop, 3) = Cells(lLoop + 2, 1)
Cells(lLoop + 1, 1).Resize(2).ClearContents
Next lLoop
With Range("A1:A" & lLastRow)
.AutoFilter field:=1, Criteria1:="="
.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
.AutoFilter
End With
End Sub
I am trying to select columns E and K from sheet Input, process in Working sheet and paste in the Output sheet after the last used row. I have stored the last used row number in x and paste the values in x+1 cell. However excel selects last row of the sheet (x as 65536) and gives run time error 4004. Can someone please help me in assisting the code.
Dim x As Long, y As String
Sheets("Input").Activate
Range("E:E,K:K").Select
Range("K1").Activate
Selection.Copy
Sheets("Working").Select
Cells(1, 1).Select
ActiveSheet.Paste
Cells.Select
Application.CutCopyMode = False
Selection.AutoFilter
Range("B5").Select
ActiveSheet.Range("$A$1:$H$30").AutoFilter Field:=1, Criteria1:="="
Cells.Select
Selection.Delete Shift:=xlUp
Columns("B:B").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("B2").Select
ActiveCell.FormulaR1C1 = _
"=IF(RC[-1]="""","""",VLOOKUP(RC[-1],Repository!C[-1]:C[1],3,0))"
Range("B2").Select
Selection.Copy
Range("B3:B30").Select
ActiveSheet.Paste
Cells.Select
Application.CutCopyMode = False
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("B2:C2").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Output").Select
Range("A1").Select
x = Worksheets("Output").UsedRange.Rows.Count
y = "a" & Trim(x + 1)
ActiveSheet("Output").Range(y).Select
ActiveSheet.Paste
Your UsedRange is still thinking that the last row is 65536. Add this subroutine, then call it right before you set x.
Sub CorrectUsedRange()
Dim values
Dim usedRangeAddress As String
Dim r As Range
'Get UsedRange Address prior to deleting Range
usedRangeAddress = ActiveSheet.UsedRange.Address
'Store values of cells to array.
values = ActiveSheet.UsedRange
'Delete all cells in the sheet
ActiveSheet.Cells.Delete
'Restore values to their initial locations
Range(usedRangeAddress) = values
End Sub
Near the bottom of your code replace:
Sheets("Output").Select
with:
Sheets("Output").Select
ActiveSheet.UsedRange
this should "re-set" UsedRange
Sometimes the Used Range gets generically large and won't reset on it's own. When this happens, the only way that I've found to force it to reset itself correctly is to Save the Workbook that the subject Worksheet is in. This works for me, on Excel 2010 anyway. Since you're using .Select and Active<obj> (which I don't recommend), it would simply be this:
ActiveWorkbook.Save
I would use a Find loop to populate an array and then output the array when the macro has completed. There is no need for a "Working" sheet. This also uses Cells(Rows.Count, "A").End(xlUp) in order to find the last populated row instead of UsedRange.Rows.Count which can be unreliable.
Sub tgr()
Dim rngFound As Range
Dim rngLookup As Range
Dim arrResults() As Variant
Dim ResultIndex As Long
Dim strFirst As String
With Sheets("Input").Columns("E")
Set rngFound = .Find("*", .Cells(.Cells.Count), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
ReDim arrResults(1 To WorksheetFunction.CountA(.Cells), 1 To 2)
Do
If rngFound.Row > 1 Then
ResultIndex = ResultIndex + 1
On Error Resume Next 'Just in case the VLookup can't find the value on the 'Repository' sheet
arrResults(ResultIndex, 1) = Evaluate("VLOOKUP(""" & rngFound.Value & """,Repository!A:C,3,FALSE)")
arrResults(ResultIndex, 2) = .Parent.Cells(rngFound.Row, "K").Value
On Error GoTo 0 'Remove the On Error Resume Next condition
End If
Set rngFound = .Find("*", rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
End With
If ResultIndex > 0 Then Sheets("Output").Cells(Rows.Count, "A").End(xlUp).Offset(1).Resize(ResultIndex, UBound(arrResults, 2)).Value = arrResults
Set rngFound = Nothing
Erase arrResults
End Sub
instead of used range check how many rows already are filled with this code:
X = WorksheetFunction.CountA(Columns(1))
Of course this only works ok if you have no rows that are empty in Column A, as those rows would be ignored!