I'm beginner at Macros I need to do a copy of rows but I have to exclude some columns. EntireRow is working but I need to exclude the columns I,G,H
Sub Macro1()
Dim RngToChk as Range, RngToPaste as Range
Set RngToCheck=Application.InputBox(Prompt:="enter range", Type:=8)
Dim strtofind as String
Inttofind=InputBox("Give your Indicator")
Dim i as long
For i = RngToChk.Rows.Count To 1 Step -1
If RngToChk(i).value=strtofind Then
RngToCheck(i).Offset(1).EntireRow.Insert
Set RngToPaste=RngToChk(i).Offset(1)
RngToPaste.EntireRow.Value=RngToChk(i).EntireRow.Value
RngToPaste.EntireRow.Font.Color=RGB(255,0,0)
End If
Next i
End Sub
Add this function to your module:
Function AlmostEntireRow(StartingPoint As Range) As Range
Dim Row As Long
Dim TargetSheet As Worksheet
Row = StartingPoint.Row
Set TargetSheet = StartingPoint.Worksheet
Set AlmostEntireRow = Union(TargetSheet.Range("A" & Row & ":F" & Row), TargetSheet.Range("J" & Row & ":GR" & Row))
End Function
When you are using it, replace
RngToPaste.EntireRow.Font.Color=RGB(255,0,0)
with
AlmostEntireRow(RngToPaste).Font.Color = RGB(255, 0, 0)
and so on.
The function builds a range from the input range, consisting of columns A to F and J to GR. Adjust as needed.
Update
The suggested method does not work when copying rows. Here is a copy method as well.
Sub CopyAlmostEntireRow(FromRow As Range, ToRow As Range)
Dim FromRange As Range
Dim ToRange As Range
Set FromRange = FromRow.Worksheet.Range("A" & FromRow.Row & ":F" & FromRow.Row)
Set ToRange = ToRow.Worksheet.Range("A" & ToRow.Row & ":F" & ToRow.Row)
ToRange.Value = FromRange.Value
Set FromRange = FromRow.Worksheet.Range("J" & FromRow.Row & ":GR" & FromRow.Row)
Set ToRange = ToRow.Worksheet.Range("J" & ToRow.Row & ":GR" & ToRow.Row)
ToRange.Value = FromRange.Value
End Sub
' Call with something like this:
CopyAlmostEntireRow RngToChk(i), RngToPaste
Related
I'm not very familiar with VBA, but am in need of a macro that would replace ### to = for columns B, F, and J without affecting rows 1 to 15.
I found the below code as my starting point, but can't seem to adjust it to my situation, or if this would even work for my situation...
this code was replacing everything in B that was not empty to Title starting at B2
Sub replace_text
Dim lrow As Long
Dim rng As Range
lrow = Cells(Rows.Count, "B").End(xlUp).Row 'Detect last data entry row in Column B.
For Each rng In Range("B2:B" & lrow)
If rng <> "" Then
rng = "Title"
End If
Next rng
End Sub
essentially, my goal is to replace every occurrences of text strings that start with ### with = without affecting the remainder of the strings.
everything in column B, F, and J starting at row 16 would start with ### but do not have the same text after the ###.
other columns would also have ### at the start but would need to remain intact
Worksheet.Evaluate: Replace Text
Sub ReplaceText()
Const FIRST_ROW As Long = 16
Const COLUMNS_RANGE As String = "B:B,F:F,J:J"
Const BEGINS_WITH_STRING As String = "###"
Const REPLACE_STRING As String = "="
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim rg As Range
With ws.UsedRange
Set rg = .Resize(.Rows.Count + .Row - FIRST_ROW).Offset(FIRST_ROW - 1)
End With
Dim arg As Range, aAddress As String, Formula As String
For Each arg In Intersect(rg, ws.Range(COLUMNS_RANGE)).Areas
aAddress = arg.Address
Formula = "IF(LEFT(" & aAddress & "," & Len(BEGINS_WITH_STRING) _
& ")=""" & BEGINS_WITH_STRING & """," & "SUBSTITUTE(" _
& aAddress & ",""" & BEGINS_WITH_STRING & """,""" _
& REPLACE_STRING & """,1)," & aAddress & ")"
'Debug.Print Formula
arg.Value = ws.Evaluate(Formula)
Next arg
MsgBox "Text replaced.", vbInformation
End Sub
I am interested in renaming my document's cell references to easily perform calculations in other sheets. In the below code I am trying to name cell Di to the concatenation of the text in Ci and the year. I am using the below code and getting an error:
Sub or Function Not Defined
Any ideas?
Sub Rename()
Dim ws As Worksheet
Set ws = ThisWorkbook.ActiveSheet
For i = 1 To 50
Dim rng As Range
Dim str As String
Set rng = Range("D" & i)
rng.Name = Range("C" & i) & "_" & "2019"
Next i
End Sub
I wanted to convert below formula to VBA code.
=C1&"`"&K1&"`"&L1&"`"&J1
=VLOOKUP(M1,Data!$A:$J,9,)
=SUMPRODUCT(SUMIF(B1:B,B1,G1:G))
Currently i have enter this formula in 1st row and than copying this formula till the last row used which is taking lot time to apply formula because it has more than million row.
LR1 = Sheets("CRIMS").UsedRange.Rows.Count
Sheets("CRIMS").Range("M1:P1").AutoFill Destination:=Sheets("CRIMS").Range("M1:P" & LR1)
is there any way to convert this formula into VBA code?
For first formula the easiest way would be:
Range("M" & i).FormulaR1C1 = "=RC[-10]&""`""&K&""`""&L&""`""&J"
But for vlookup I prefer dictionaries/collections! It is much much faster.
If You have source data in Data sheet and You want to put that to CRIMS sheet to column M:
Sub vlookup()
Dim names As Range, values As Range
Dim lookupNames As Range, lookupValues As Range
Dim vlookupCol As Object
Dim lastRow As Long
Dim lastRow2 As Long
Dim objekt as Object
With Sheets("Data")
lastRow = Sheets("Data").Cells(Rows.Count, 1).End(xlUp).row
Set names = Sheets("Data").Range("A1:A" & lastRow)
Set values = Sheets("Data").Range("I1:A" & lastRow)
End With
Set objekt = BuildLookupCollection(names, values)
With Sheets("CRIMS")
lastRow2 = 1000000
Set lookupNames = .Range("M1:M" & lastRow)
Set lookupValues = .Range("N1:N" & lastRow)
End With
VLookupValues lookupNames, lookupValues, objekt
Set objekt = Nothing
End Sub
Function BuildLookupCollection(categories As Range, values As Range)
Dim vlookupCol As Object, i As Long
Set vlookupCol = CreateObject("Scripting.Dictionary")
On Error Resume Next
For i = 1 To categories.Rows.Count
Call vlookupCol.Add(CStr(categories(i)), values(i))
Next i
On Error GoTo 0
Set BuildLookupCollection = vlookupCol
End Function
Sub VLookupValues(lookupCategory As Range, lookupValues As Range, vlookupCol As Object)
Dim i As Long, resArr() As Variant
ReDim resArr(lookupCategory.Rows.Count, 1)
For i = 1 To lookupCategory.Rows.Count
resArr(i - 1, 0) = vlookupCol.Item(CStr(lookupCategory(i)))
Next i
lookupValues = resArr
End Sub
Quotation Marks need to be doubled in VBA
Try this:
For i = 1 To LR1
Range("M" & i).Formula = "=C" & i & "&""`""&K" & i & "&""`""&L" & i & "&""`""&J" & i
Range("N" & i).Formula = "=VLOOKUP(M" & i & ",Data!$A:$J,9,)"
Next i
(replace column letters with actual target column)
As mentioned in the comments Looping in this case is highly inefficient.
Use this Code to insert the formulas all at once. It still takes some time for 1 Milion rows though.
Range("M1:M" & LR1).Formula = "=C:C & ""`"" & K:K & ""`"" & L:L & ""`"" & J:J"
Range("N1:N" & LR1).Formula = "=VLOOKUP(M:M,Data!$A:$J,9,)"
With the union statement I created a range existing of multiple subranges, of Worksheet("data"). I need that range for calculations on another worksheet, Worksheet("weekly"). Therefore I want the address of the range including the sheet name in each subrange. rRng is my range existing of several subranges.
rRng.Address(External:=True) returns: "data!$D$1570:$D$1575,$D$2992:$D$3000,$D$5979:$D$5988"
However, to calculate the average of the cells in this range I need: "data!$D$1570:$D$1575,data!$D$2992:$D$3000,data!$D$5979:$D$5988"
The only solution I found so far is:
Dim range_string As String
range_string = ""
Dim SubRange As range
For Each SubRange In rRng
range_string = range_string & SubRange.Address(External:=True) & ","
Next SubRange
range_string = Left(range_string, (Len(range_string) - 1))
Worksheets("weekly").range("$C2").Formula = "=AVERAGE(" & range_string & ")"
There must be a more easy way. Any suggestions?
Kind regards,
Sandra
Each of those subranges is called an Area. You can loop through the Areas of a range and build the string. Here's an example.
Sub test()
Dim rng As Range
Dim rArea As Range
Dim sForm As String
'union the ranges
Set rng = Sheet1.Range("D1570:d1575")
Set rng = Union(rng, Sheet1.Range("D2992:d3000"))
'loop through the areas and build the string
For Each rArea In rng.Areas
sForm = sForm & rArea.Address(, , , True) & ","
Next rArea
'remove the last comma
sForm = Left$(sForm, Len(sForm) - 1)
'insert the formula
Sheet2.Range("A1").Formula = "=AVERAGE(" & sForm & ")"
Debug.Print Sheet2.Range("A1").Formula
End Sub
The debug.print produces:
=AVERAGE(data!$D$1570:$D$1575,data!$D$2992:$D$3000)
Newbie question: I have module, originally made by Roger Govier.
It uses an input cell header and creates a dynamic named range for the non empty cells positioned under header. The created named range will be labeled as the value of the header cell.
Private Sub CreateNamedRange(header As range)
Dim wb As Workbook
Dim WS As Worksheet
Dim rStartCell As range
Dim rData As range
Dim rCol As range
Dim lCol As Long
Dim sSheet As String
Dim Rowno As Long
' get table location
Set rStartCell = header
Set WS = rStartCell.Worksheet
Set wb = WS.Parent
sSheet = "'" & WS.Name & "'"
With rStartCell
Rowno = .row
Set rData = .CurrentRegion
End With
Set rData = WS.range(rStartCell, WS.Cells(Rowno, rStartCell.Column))
Set rCol = rData.Columns
lCol = rCol.Column
wb.Names.Add Name:=Replace(rCol.Cells(1).Value, " ", "_"), _
RefersToR1C1:="=" & sSheet & "!" & rCol.Cells(2).Address(ReferenceStyle:=xlR1C1) & ":INDEX(C" & lCol & ",LOOKUP(2,1/(C" & lCol & "<>""""),ROW(C" & lCol & ")))"
End Sub
I want to modify this code so that instead of creating a named range it only returns the returns the range of the what would have been the named range.
Example:
We have a header in A1, and data in A2:A5.
Now: If we call CreateNamedRange(.range("A1")), it creates a dynamic named range for A2:A5.
Goal: If we call CreateNamedRange(.range("A1")) it returns .range("A2:A5") to a variable in the VBA code:
dim myRange As Range
set myRange = CreateNamedRange(.range("A1"))
First thing you should note is that Subs do not return any value and thus myRange = CreateNamedRange(.range("A1")) does not make any sense (with your Sub; it does make sense with the Function in this answer).
The function below returns a range, in the same column that the input range, starting from the next row and including all the ones below until finding a blank cell. This range is called "anyName" (and thus you can access it via Range("anyName")).
Private Function CreateNamedRange(header As Range) As Range
Dim curRow As Long: curRow = header.Row + 1
Set tempRange = header.Worksheet.Cells(curRow, header.Column)
Do While (Not IsEmpty(tempRange))
curRow = curRow + 1
Set tempRange = header.Worksheet.Cells(curRow, header.Column)
Loop
Set CreateNamedRange = header.Worksheet.Range(header.Worksheet.Cells(header.Row + 1, header.Column), header.Worksheet.Cells(curRow, header.Column))
CreateNamedRange.Name = "anyName"
End Function
If you already have the beginning cell activated you can just use
Set myRange = Range(ActiveCell.Address, ActiveCell.Offset.End(xlDown).Address)
to set your range for all entries below the active cell. If you don't have it activated, you can just use your rstartCell reference with an offset
Set myRange = Range(rStartCell.Offset(1), rStartCell.Offset(1).Offset.End(xlDown).Address)
Then you can just add the named range in the next line