Paste a range variable at the location of another variable - vba

Im setting the location I want to paste at with column_find. I want to paste a range (user_data) at that cell. The macro runs but only pastes 1 value from the range. What am I doing wrong?
Sub Column_Locate()
Dim current_month As Variant
Dim column_find As Range
Dim user_data As Range
current_month = Worksheets("Inputs").Cells(4, 4).Value
Set column_find = Worksheets("Feeder").Range("E2:CZ2").Find(current_month, LookIn:=xlValues, LookAt:=xlWhole).Offset(8, -1)
Debug.Print column_find.Address(0, 0)
Set user_data = Worksheets("Unique Users Data").Range("B2:C3")
Worksheets("Feeder").Select
column_find = user_data
End Sub

you have to adjust the size of "target" range (i.e. column_find) accordingly to the "source" one (i.e. user_data)
also avoid use of Select/Selection/Activate/ActiveXXX pattern , which is both time consuming and prone to have you quickly lose control over your ranges reference and adopt a fully qualified range reference pattern (for instance with the use of With... End With construct)
so you would code (explanations in comments):
Option Explicit
Sub Column_Locate()
Dim current_month As Variant
Dim column_find As Range
Dim user_data As Range
current_month = Worksheets("Inputs").Cells(4, 4).Value
Set user_data = Worksheets("Unique Users Data").Range("B2:C3")
With Worksheets("Feeder") 'reference "Feeder" worksheet
Set column_find = .Range("E2:CZ2").Find(current_month, LookIn:=xlValues, LookAt:=xlWhole).Offset(8, -1) 'search referenced sheet range "E2:CZ2" for 'current_month' value
If Not column_find Is Nothing Then 'if the searched value has been found
With user_data 'reference "source" range
Debug.Print column_find.Address(0, 0)
column_find.Resize(.Rows.Count, .Columns.Count).Value = user_data.Value ' reference a "target" range as the one with found value but with same size as "source" range and write values
End With
End If
End With
End Sub

Related

Index match match/vlookup in VBA

I have an Excel document with two different Sheets. Sheet 2 has columns header names and rows header names. Sheet 1 has some of these columns with exact header names and rows header names but it's filled with data.
enter image description here, enter image description here
I want to make a macro that will look through all the column/rows headers in Sheet 1 and find their corresponding match in Sheet2. When the match is found, I need to copy the entry of the Sheet column/row header into the matching header of sheet2. Some entries in Sheet2 will not have matches and will remain blank.
I want it to look like this:
enter image description here
This is my code so far, it is working for the column headers but I don't know how to add for row headers as well. Any help is welcomed :)
Sub CopyData()
Application.ScreenUpdating = False
Dim LastRow As Long, header As Range, foundHeader As Range, lCol As Long, srcWS As Worksheet, desWS As Worksheet
Set srcWS = Sheets("Sheet1")
Set desWS = Sheets("Sheet2")
LastRow = srcWS.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
lCol = desWS.Cells(3, Columns.Count).End(xlToLeft).Column
For Each header In desWS.Range(desWS.Cells(3, 2), desWS.Cells(3, lCol))
Set foundHeader = srcWS.Rows(2).Find(header, LookIn:=xlValues, lookat:=xlWhole)
If Not foundHeader Is Nothing Then
srcWS.Range(srcWS.Cells(3, foundHeader.Column), srcWS.Cells(LastRow, foundHeader.Column)).Copy desWS.Cells(4, header.Column)
End If
Next header
Application.ScreenUpdating = True
End Sub
You can use built-in Range.Consolidate method (https://learn.microsoft.com/en-us/office/vba/api/excel.range.consolidate):
(Edit2)
Option Explicit
Sub ConsolidateThis()
Dim rng1 As Range, rng2 As Range, addr As String
With ThisWorkbook
' determine source and destination ranges
Set rng1 = getTableRange(.Worksheets("Sheet1").Range("A2"))
Set rng2 = getTableRange(.Worksheets("Sheet2").Range("A3"))
' make full address of consolidated range like "'[Consolidate.xlsm]Sheet1'!R3C1:R6C5"
addr = "'[" & .Name & "]" & rng1.Parent.Name & "'!" & rng1.Address(ReferenceStyle:=xlR1C1)
' do consolidation
rng2.Consolidate Sources:=Array(addr), Function:=xlSum, TopRow:=True, LeftColumn:=True
End With
End Sub
' Returns the range that starts with the top left corner cell and is bounded
' on the right and bottom by empty cells
Function getTableRange(LeftTopCornerCell As Range) As Range
Dim ws As Worksheet, rightEdge As Long, downEdge As Long
With LeftTopCornerCell(1)
Set ws = .Parent
rightEdge = ws.Cells(.Row, ws.Columns.Count).End(xlToLeft).Column
downEdge = ws.Cells(ws.Rows.Count, .Column).End(xlUp).Row
End With
Set getTableRange = ws.Range(LeftTopCornerCell(1), ws.Cells(downEdge, rightEdge))
End Function
Your best solution might to set 2 ranges, each taking values from tables in Sheet1 and Sheet2. Let's call them rgSrcTable and rgDestTable. Then you need to loop using For Each through each range and compare top and left headers, and when you find a match, copy the value of the cell in rgSrcTable to the cell in rgDestTable.
Edit: Code sample. Feel free to adapt ranges to your needs. Since this routine used Range.Value property, you can filter any data (string, numbers, etc.)
Option Explicit
Sub CopyDataWithFilter()
Dim iRowHeader As Integer, iColHeader As Integer
Dim rngSrc As Range, rngDest As Range, celSrc As Range, celDest As Range
iRowHeader = 2
iColHeader = 1
With ThisWorkbook
' Set source and destination ranges. Modify ranges according to your needs
Set rngSrc = .Worksheets("shtSrc").Range("$B$3:$E$5")
Set rngDest = .Worksheets("shtDest").Range("$B$3:$E$5")
' Loop through source range and dest range
For Each celDest In rngDest
For Each celSrc In rngSrc
' Compare top headers and left headers respectively. If matching, copy the value in destination table.
If .Worksheets("shtSrc").Cells(celSrc.Row, iColHeader).Value = .Worksheets("shtDest").Cells(celDest.Row, iColHeader).Value And _
.Worksheets("shtSrc").Cells(iRowHeader, celSrc.Column).Value = .Worksheets("shtDest").Cells(iRowHeader, celDest.Column).Value Then
celDest.Value = celSrc.Value
End If
Next celSrc
Next celDest
End With
End Sub
Result:

VBA Includes empty cells in table formatting

Very new to VBA.
What I am trying to do:
1) Copy sheet from (source) workbook to active (master) workbook
2) Delete unnecessary columns of the copied data in the master workbook
3) Select cells with data in the master workbook and format as table (this is where I am stuck)
Sub first_sub()
'Open user Raw Data workbook
Workbooks.Open Filename:= _
"C:\Users\" & Environ("UserName") & "\Downloads\File.xls"
'Copy user Raw Data sheet to Data Master sheet
Workbooks("File.xls").Sheets("Records").Copy _
Before:=Workbooks("Macro Main.xlsm").Sheets(1)
'Close user Raw Data
Workbooks("File.xls").Close
End Sub
Sub Format()
Sheets("Records").Range("D:G,I:K,M:Y,AA:AA,AF:AM").EntireColumn.Clear
Sheets("Records").Range("D:G,I:K,M:Y,AA:AA,AF:AM").EntireColumn.Delete
End Sub
Sub MakeTable()
Dim tbl As ListObject
Dim rng As Range
Set rng = Range(Range("A1"), Range("A1").SpecialCells(xlLastCell))
Set tbl = ActiveSheet.ListObjects.Add(xlSrcRange, rng, , xlYes)
tbl.TableStyle = "TableStyleMedium3"
End Sub
The problem is in point 3. For some reasons, VBA selects columns up to "AM", even though I deleted them in previous sub, and as a result - I have the table full of empty columns all the way up to AM. How to solve this? Thank you in advance.
Check how .SpecialCells(xlLastCell) works: Range.SpecialCells Method (Excel)
I think your range variable rng is referencing from range Range("A1") to the last used cell in the column range AM
Set rng = Range(Range("A1"), Range("A1").SpecialCells(xlLastCell))
Try adding this line after to check if the range is actually targeting your desired range:
rng.select
To solve this problem you can try:
Set rng = Range("A1").CurrentRegion
Or finding the last cell in column A...
Code:
Sub MakeTable()
Dim tbl As ListObject
Dim rng As Range
Set rng = Range("A1").CurrentRegion
Set tbl = ActiveSheet.ListObjects.Add(xlSrcRange, rng, , xlYes)
tbl.TableStyle = "TableStyleMedium3"
End Sub

Search words in range on Sheet1 in list of words on Sheet2 and if match then clear word on Sheet1

I have a list of names on one sheet (InputSheet) in the range c6:H200. The names in this range change twice a month. The group of names in the InputSheet are compared to a list of names on another sheet (NameList) in the range e2:e50. For each name that is found on the NameList, I want to remove the name on the InputSheet. I'm new to vba but have written this code and it is not working (getting run time error). Thanks for any help!
Sub RemoveNonWords()
Dim datasheet As Worksheet
Dim cl As Range
Set wordrange = InputSheet.Range("C6:h200")
Set datasheet = NameList.Range("E1:E50").Value
For Each cl In wordrange
If cl = datasheet Then
cl.Selection.ClearContents
End If
Next
Range("A6").Select
End Sub
There's a lot wrong with your posted code. I think in the end, this is what you're looking for, code commented for clarity:
Sub tgr()
Dim wb As Workbook
Dim wsInput As Worksheet
Dim wsNames As Worksheet
Dim rInputData As Range
Dim rNameList As Range
Dim DataCell As Range
Dim rClear As Range
Dim lRow As Long
Set wb = ActiveWorkbook
Set wsInput = wb.Sheets("InputSheet") 'Change to the actual sheet name of your input sheet
Set wsNames = wb.Sheets("NameList") 'Change to the actual sheet name of your name list sheet
'Get last used row of the C:H columns in wsInput
With wsInput.Range("C:H")
lRow = .Find("*", .Cells(1), , , , xlPrevious).Row
If lRow < 6 Then Exit Sub 'No data
End With
'Use the last used row to define your inputdata range, this was hardcoded to C6:H200 in your question
Set rInputData = wsInput.Range("C6:H" & lRow)
'Define the namelist range using all populated cells in column E of wsNames, this was hardcoded to E2:E50 in your question
Set rNameList = wsNames.Range("E2", wsNames.Cells(wsNames.Rows.Count, "E").End(xlUp))
If rNameList.Row < 2 Then Exit Sub 'No data
'Data has been found and ranges assigned
'Now loop through every cell in rInputData
For Each DataCell In rInputData.Cells
'Check if the cell being looked at exists in the NameList range
If WorksheetFunction.CountIf(rNameList, DataCell.Value) > 0 Then
'Found to exist, add the cell to the Clear Range
If rClear Is Nothing Then
Set rClear = DataCell 'First matching cell added
Else
Set rClear = Union(rClear, DataCell) 'All subsequent matching cells added
End If
End If
Next DataCell
'Test if there were any matches and if so clear their contents
If Not rClear Is Nothing Then rClear.ClearContents
End Sub

Excel VBA: Copy and paste selection based off row and column headers

I am trying to create a macro that will format and create a weekly report.
It has five columns that need to be moved: Key, Summary, Created, Status, Fix Version/s.
I need to copy a selection that starts at Row 2 in the Key column and ends at the last row in the Fix Version/s column that will then be pasted into a sheet called "Priority Issues". I am unsure how to code this specific selection.
I need to store the last row in a variable, as the last row may change from week to week. In essence, I am looking for code that allows me to make a selection from the intersection of row 2 and the Key column to the intersection of the last row and the Fix Version/s column, but am unsure how to do that.
Function FindCol(toFind As String) As Range
Dim Rtn As Range
Set Rtn = Rows(1).Find(What:=toFind, LookIn:=xlValues, _
LookAt:=xlWhole, MatchCase:=True)
Set FindCol = Rtn
End Function
Sub Move_Severity()
Dim Severity As Range
Dim Key As Range
Dim Fix_Version As Range
Dim LastRow As Long
Set Severity = FindCol("Severity")
Set Key = FindCol("Key")
Set Fix_Version = FindCol("Fix Version/s")
LastRow = Cells(Rows.Count, Severity.Column).End(xlUp).Row
'This is where I am running into problems
Range(Cells(2, Key), Cells(LastRow, Fix_Version)).Copy
Sheets("Priority Issues").Range("A2").Paste
End Sub
Sub Move_Severity()
Dim Severity As Range
Dim Key As Range
Dim Fix_Version As Range
Dim LastRow As Long
Set Severity = FindCol("Severity")
Set Key = FindCol("Key")
Set Fix_Version = FindCol("Fix Version/s")
With ActiveSheet '<~~ change active sheet reference to whatever must it be
.Range(.Cells(2, Key.Column), .Cells(.Rows.Count, Severity.Column).End(xlUp)).Copy Destination:=Sheets("Priority Issues").Range("A2")
End With
End Sub
should you only need to paste values then change that With-End With part to
With ActiveSheet
With .Range(.Cells(2, Key.Column), .Cells(.Rows.Count, Severity.Column).End(xlUp))
Sheets("Priority Issues").Range("A2").Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
End With
which is much faster

Why won't my sub using the .Copy method grab both reference ranges unless I run the sub twice?

I have cobbled together a subroutine to get two ranges of data from blocks of cells in two separate worksheets. Then, using the .Copy method, it puts the first block into (1, 1) of a third worksheet and the second block into the next available row of that worksheet.
The code I have written pretty much does what I want it to do, except that for some reason it will not paste the second range (declared as DataRng2 below) unless the sub is run twice in a row. Here is what I have:
Sub Test()
Dim DataRng As Range
Dim DataRng2 As Range
Dim Test As Worksheet
Dim EmtyRow As Range
Application.ScreenUpdating = False
Set Test = Worksheets("Test")
'Set the "EmptyRow" reference to whatever the next empty row is in the destination worksheet - checks column A
Set EmptyRow = Worksheets("Test").Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
'Select all utilized cells in 82-Medicine tab and copy them
Worksheets("82-Medicine").Select
Set DataRng = Worksheets("82-Medicine").Cells(2, 1).CurrentRegion
'Select the destination worksheet and paste copied cells to A1
Test.Select
DataRng.Copy Cells(1, 1)
'Select all utilized cells in Fee Basis tab and copy them
Worksheets("Fee Basis").Select
Set DataRng2 = Worksheets("Fee Basis").Cells(2, 1).CurrentRegion
'Select the destination worksheet and paste copied cells to the next empty row
Test.Select
DataRng2.Copy EmptyRow
Application.ScreenUpdating = True
End Sub
Why do I have to run it twice to get it to work? Is there a way to fix that?
I should note that I am using the .CurrentRegion property to get the data only because rows of data will frequently be added to and subtracted from the ranges of cells I need to grab, and .CurrentRegion is the simplest way I know to grab the first range of whatever cells are occupied. I am open to using a different property or method if necessary.
Option Explicit
Sub Test()
Dim src_1 As Worksheet
Dim src_2 As Worksheet
Dim dest As Worksheet
Dim src_1_rng As Range
Dim src_2_rng As Range
Dim lr As Integer
Dim lc As Integer
Set src_1 = ThisWorkbook.Sheets("82-Medicine")
Set src_2 = ThisWorkbook.Sheets("FeeBasis")
Set dest = ThisWorkbook.Sheets("Test")
'' Set up range for data from '82-Medicine'
lr = src_1.Cells(2, 1).End(xlDown).Row
lc = src_1.Cells(2, 1).End(xlToRight).Column
Set src_1_rng = src_1.Range(src_1.Cells(2, 1), src_1.Cells(lr, lc))
'' Set up range for data from 'FeeBasis'
lr = src_2.Cells(2, 1).End(xlDown).Row
lc = src_2.Cells(2, 1).End(xlToRight).Column
Set src_2_rng = src_2.Range(src_2.Cells(2, 1), src_2.Cells(lr, lc))
'' Copy the data to the destination sheet ('Test')
src_1_rng.Copy dest.Range("A" & dest.Rows.Count).End(xlUp).Offset(1)
src_2_rng.Copy dest.Range("A" & dest.Rows.Count).End(xlUp).Offset(1)
End Sub
Not sure why that wouldn't work but try this. I've never been a fan of CurrentRegion or selecting different sheets during code. Why bother when you can just use references? This should work perfectly.
edit
Changed the lr and lc variables to use xlDown from (2,1) and xlToRight from (2,1) to properly get a "CurrentRegion"-esque range.