Using For Each and the Find method, I can look for a cell in a range even if the range is multiple columns by multiple rows. But how can I look for a set of cells in a range?
For example, I have a reference book whose row entries fill rows 2-7 and are two columns wide. I need to find if they have an exact match to the row entries (which also begin in row 2 and are two columns wide) in my target book. If it finds a match, it pastes the row # from the reference file into column 5. Otherwise, it pastes in the new entry. Here's the code so far:
Dim NewFile as Workbook 'defined as the location of the reference book
Dim NewSht as Worksheet 'defined as the sheet in NewFile
Dim ThisSht as Worksheet 'defined as the sheet in the target book
Dim NewName as Range
Dim LastEntry as Range
Dim OldNameRange as Range
Dim EntryMatch as Range
For Each NewName In NewSht.Range(NewSht.Cells(2, 1), NewSht.Cells(Rows.Count, 2).End(xlUp)) 'loops thru each set of entry labels in new sheet
Set LastEntry = ThisSht.Cells(Rows.Count, 2).End(xlUp)
Set OldNameRange = ThisSht.Range(ThisSht.Cells(2, 1), LastEntry)
Set EntryMatch = OldNameRange.Find(NewName.Value, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=True)
If Not EntryMatch Is Nothing Then
ThisSht.Cells(EntryMatch.Row, 5).Value = NewName.Row
Else
ThisSht.Cells(LastEntry.Row + 1, 1).Resize(1, 2).Value = NewSht.Range(NewSht.Cells(NewName.Row, 1), NewName.Cells(NewName.Row, 2)).Value
ThisSht.Cells(LastEntry.Row + 1, 3).Value = NewName.Row
End If
Next
Right now, it's only comparing cell by cell. Can anyone help me get it to compare a set of cells (each row of entries) against each set of cells in the OldNameRange? Thanks!
Related
I'm a little stuck at the moment on the problem - I have a workaround but it's very inefficient and also very time consuming to code.
I have a selection of worksheets and I would like to add a different header row to each of these sheets based on the sheet name.
I would like to have a worksheet containing a selection of header rows - see Selection of Header Rows
Then, for example, if the worksheets = A00 - apply the copy in the corresponding Header Row from the Selection worksheet.
This is my current solution - as you can see it is very inefficient and time-consuming
For Each myWorksheet In Worksheets
If myWorksheet.Name = "A00" Then
Sheets("A00").Cells(1).Resize(1, 5).Value = Array("ORGANISATION_ID", "FILE_TYPE", "CREATION_DATE", "CREATION_TIME", "GENERATION_NUMBER")
End If
If myWorksheet.Name = "Z99" Then
Sheets("Z99").Cells(1).Resize(1, 1).Value = Array("RECORD_COUNT")
End If
If myWorksheet.Name = "I56" Then
Sheets("I56").Cells(1).Resize(1, 26).Value = Array("ORGANISATION_SHORT_CODE", "INVOICE_NUMBER", "INVOICE_TYPE_CODE", "BILLING_YEAR", "BILLING_MONTH", "INVOICE_AMOUNT", "INVOICE_VAT_AMOUNT", "INVOICE_GROSS_TOTAL", "PAYMENT_DUE_DATE", "VAT_CHARGED_TO_NWO", "VAT_CHARGED_TO_SHIPPER", "INVOICE_TAX_POINT_DATE", "NWO_VAT_ REGISTRATION_NUMBER", "NWO_BANK_SORT_CODE", "NWO_BANK_ACCOUNT_NUMBER", "NWO_BANK_ACCOUNT_NAME", "ISH_VAT_REGISTRATION_NUMBER", "ISH_BANK_ACCOUNT_NUMBER", "ISH_BANK_SORT_CODE", "NWO_SHORT_CODE", "NWO_VAT_REGISTRATION_NAME", "NWO_ADDRESS_LINE_1", "NWO_ADDRESS_LINE_2", "NWO_ADDRESS_LINE_3", "NWO_ADDRESS_LINE_4", "FILE_NAME")
End If
If myWorksheet.Name = "I05" Then
Sheets("I05").Cells(1).Resize(1, 2).Value = Array("ISC_LINE_1_TEXT", "ISC_LINE_2_TEXT")
End If
If myWorksheet.Name = "I57" Then
Sheets("I57").Cells(1).Resize(1, 8).Value = Array("INVOICE_ITEM_REFERENCE_NUMBER", "INCURRED_DATE", "CHARGE TYPE CODE", "QUANTITY", "UNIT_TYPE", "RATE", "INVOICE_ITEM_AMOUNT", "ANCILLARY_INVOICE_COMMENTS")
End If
If myWorksheet.Name = "K12" Then
Sheets("K12").Cells(1).Resize(1, 4).Value = Array("GAS_ACT_OWNER", "CURRENT_METER_ASSET_MANAGER", "PROSPECTIVE_METER_ASSET_MANAGER", "PROSPECTIVE_MAM_EFFECTIVE_DATE")
End If
Next myWorksheet
Any help with this would be much appreciated.
Create a worksheet called Index and populate it as you have done in the image.
Then, the following code will work through each tab and if the tab name is found in column A it will copy the entire row below that cell into the first row of the tab.
For Each myworksheet In Worksheets
rowfound = Application.Match(myworksheet.Name, Worksheets("Index").Range("A:A"), 0)
If Not (IsError(rowfound)) Then myworksheet.Range("1:1").Value = Worksheets("index").Cells(rowfound + 1, 1).EntireRow.Value
Next
I think I would approach this by doing the steps listed below, with the following assumptions about your worksheets.
The worksheet in your image is named "Selection of Header Rows".
The worksheet in your image will have empty rows between the header
listings as pictured.
The first column pictured in your image is
Column A.
You want the headers to start in Cell A1 of the individual
sheets.
Steps
Define a range of the pictured worksheet in which we'll search for each worksheet's name.
Loop through each worksheet in the collection, finding its name in our search range.
If the name is found, define a range by using the CurrentRegion property of the range in which the name was found. (The current region is a range bounded by any combination of blank rows and blank columns.)
Count the columns in that range.
Offset that range down one row (to exclude the sheet name itself).
Resize that range to be one row "high" and the same number of columns "wide".
Set the header range on the target sheet to be the cell A1 and resize it to have the correct number of columns.
Set the value of that header range equal to the value of the range we built on the "Selection of Header Rows" worksheet.
Dim myWorksheet As Worksheet
Dim searchRange As Range
Set searchRange = Worksheets("Selection of Header Rows").Range("A:A")
Dim foundRange As Range
Dim headerRange As Range
For Each myWorksheet In Worksheets
Set foundRange = searchRange.Find(What:=myWorksheet.Name, LookAt:=xlWhole)
If Not foundRange Is Nothing Then
Set headerRange = foundRange.CurrentRegion.Offset(1, 0)
Dim headerColumnCount As Long
headerColumnCount = headerRange.Columns.Count
Set headerRange = headerRange.Resize(1, headerColumnCount)
myWorksheet.Range("A1").Resize(1, headerColumnCount).value = headerRange.value
End If
Next myWorksheet
I am trying to copy a specified range of cells from one sheet (Sheet2) to a specified range of cells in another sheet (Sheet1) based on a condition. There are hundreds of rows of data, and I would like VBA code that looks at each row, and if the condition is met for that row, copies the specified cell range from sheet2 to sheet1. It is not the entire row being copied, just four cells out of a row with many more cells that contain data.
In more specific terms, I would like to copy columns B through E for each row (starting at row 2) IF the value in column AK for each row is greater than 0. I would like for this data to be pasted into columns B through E in sheet1, starting at row 8. So, for example, if row 2 in Sheet 2 meets the criteria, I would like for B2 through E2 in sheet 2 to be copied to B8 through E8 in sheet 1.
I have tried to adapt code found in other questions on StackOverFlow and other sources but I am very new to VBA and have not been successful. Any help would be greatly appreciated.
Private Sub CopySomeCells()
Dim SourceSheet As Worksheet
Dim DestinationSheet As Worksheet
Dim SourceRow As Long
Dim DestinationRow As Long
Set SourceSheet = ActiveWorkbook.Sheets(2)
Set DestinationSheet = ActiveWorkbook.Sheets(1)
DestinationRow = 8
For SourceRow = 2 To SourceSheet.UsedRange.Rows.Count
If SourceSheet.Range("AK" & SourceRow).Value > 0 Then
SourceSheet.Range(SourceSheet.Cells(SourceRow, 2), SourceSheet.Cells(SourceRow, 5)).Copy _
DestinationSheet.Cells(DestinationRow, 2)
DestinationRow = DestinationRow + 1
End If
Next SourceRow
Application.CutCopyMode = False
Set SourceSheet = Nothing
Set DestinationSheet = Nothing
End Sub
If you just want to paste the values (and not the format) then change two rows by this:
SourceSheet.Range(SourceSheet.Cells(SourceRow, 2), SourceSheet.Cells(SourceRow, 5)).Copy
DestinationSheet.Cells(DestinationRow, 2).PasteSpecial Paste:=xlPasteValues
Or better by this (faster and without clipboard):
DestinationSheet.Cells(DestinationRow, 2).Resize(1, 4).Value = _
SourceSheet.Cells(SourceRow, 2).Resize(1, 4).Value
I have a range of cell numbers that I need for multiple worksheet names.
I create multiple worksheets based on the number of rows.
Sub Copier()
Dim x As Integer
x = InputBox("Enter number of times to copy worksheet")
For numtimes = 1 To x
ActiveWorkbook.Sheets("OMRS 207").Copy _
After:=ActiveWorkbook.Sheets("OMRS 207")
Next
End Sub
That grabs only one name, OMRS 207.
I want to generate these worksheets using the entire range of cells in the original worksheet.
Try below code.
Dim data As Worksheet
Dim rng As Range
Set data = ThisWorkbook.Sheets("Sheet1")
Set rng = data.Range("A2")
Do While rng <> ""
ThisWorkbook.Worksheets.Add
ActiveSheet.Name = rng.Value
Set rng = rng.Offset(1, 0)
Loop
I assumed that your data starts from 2nd row in Sheet1 and you want the sheet name as per values in Column A.
If you want row number as sheet name for newly added sheet just use rng.row while assigning name to sheet.
I've tried various ways and answers to select all of the rows except the header for a certain column and none seem to work.
I've tried using (15 is the column here):
Range(Cells(2, 15), Cells(.Cells(rows.Count, 15).End(xlUp).Row, 15)).Select
I managed to use .Activate on the worksheet with a different statement to select all, but this changes the sheet and you could visibly see all the rows being selected. This isn't possible for what I need it for. Users can't have a bunch of sheets constantly being switched in front of them, makes for a bad experience.
How can I select all of the non-blank columns after the header (first) row without using .Activate?
I need to get these values, put them in an array, and check if the current cell value is in the array. Not asking for this part, but providing it as context if it matters.
You can not select a range on a non-active worksheet.
Here is how you can set a reference to all the cells in a column except the header row.
Dim TargetRange As Range
With Worksheets("Sheet1")
Set TargetRange = .Range(.Cells(2, 15), .Cells(Rows.Count, 15).End(xlUp))
End With
The following code reads the data from the Worksheet (without using Select or Activate), and puts it in a 2-dimensional array.
Option Explicit
Sub Range_WO_Headers()
Dim Sht_Source As Worksheet
Dim Rng As Range
Dim LastRow As Long
Dim LastCol As Long
Dim Rng_Array As Variant
' modify Sheet1 according to your sheet name
Set Sht_Source = ActiveWorkbook.Worksheets("Sheet1")
' assuming the table's data starts from Cell A1
LastRow = Sht_Source.Cells(Sht_Source.Rows.Count, "A").End(xlUp).Row
LastCol = Sht_Source.Cells(1, Sht_Source.Columns.Count).End(xlToLeft).Column
' resize array according to number of columns and number of rows
ReDim Rng_Array(0 To LastRow, 0 To LastCol)
' set dynamic array from Cell A1 to last row and last column found (starting the second row)
Set Rng = Sht_Source.Range(Cells(2, 1), Cells(LastRow, LastCol))
Rng_Array = Application.Transpose(Rng)
End Sub
I am fairly new to Excel VBA and have been trying to look for (as well as come up with my own) solutions to a dilemma I am facing. Routinely, I receive raw data files from a colleague and these raw data files may have varying number of columns but consistent header names. I have in my workbook, a master spreadsheet that I want to keep up to date by appending the new data (so keep appending data of new spreadsheet to next empty row). I would like to create a macro that can take the imported spreadsheet (say, spreadsheet A) and look at the header value of a column, copy the column range (starting from row 2 to end of populated within column), go to spreadsheet Master, look for header value, and paste the column range in the next empty cell down in the column. And this procedure would be for all columns present in spreadsheet A.
Any help/guidance/advice would be very much appreciated.
Ex) I have "master" sheet and "imported" sheet. I want to take the "imported" sheet, look at headers in row 1, starting from column 1. If that header is present in "master" sheet, copy the column (minus the header) from "imported sheet" and paste into "master" under the appropriate column header starting from the next empty cell in that column. What I ultimately want to do is keep the "master" sheet with historical data but the "imported" sheet contains columns which moves around so I just couldn't copy and paste the range starting from next empty cell in master.
Untested but compiles OK:
Sub CopyByHeader()
Dim shtA As Worksheet, shtB As Worksheet
Dim c As Range, f As Range
Dim rngCopy As Range, rngCopyTo
Set shtA = ActiveSheet ' "incoming data" - could be different workbook
Set shtB = ThisWorkbook.Sheets("Master")
For Each c In Application.Intersect(shtA.UsedRange, shtA.Rows(1))
'only copy if >1 value in this column (ie. not just the header)
If Len(c.Value) > 0 And Application.CountA(c.EntireColumn) > 1 Then
Set f = shtB.Rows(1).Find(what:=c.Value, LookIn:=xlValues, _
LookAt:=xlWhole)
If Not f Is Nothing Then
Set rngCopy = shtA.Range(c.Offset(1, 0), _
shtA.Cells(Rows.Count, c.Column).End(xlUp))
Set rngCopyTo = shtB.Cells(Rows.Count, _
f.Column).End(xlUp).Offset(1, 0)
'copy values
rngCopyTo.Resize(rngCopy.Rows.Count, 1).Value = rngCopy.Value
End If
End If
Next c
End Sub
EDIT: updated to only copy columns which have any content, and to only copy values
I cannot get the above to work, and need the same result as the original question. Any thoughts on what is missing? I thought I changed everything that needed to be changed to fit my sheets:
Sub CopyByHeader()
Dim shtMain As Worksheet, shtImport As Worksheet
Dim c As Range, f As Range
Dim rngCopy As Range, rngCopyTo
Set shtImport = ActiveSheet
' "Import"
Set shtMain = ThisWorkbook.Sheets("Main")
For Each c In Application.Intersect(shtImport.UsedRange, shtImport.Rows(1))
'only copy if >1 value in this column (ie. not just the header)
If Len(c.Value) > 0 And Application.CountA(c.EntireColumn) > 1 Then
Set f = shtMain.Rows(1).Find(what:=c.Value, LookIn:=xlValues, _
LookAt:=xlWhole)
If Not f Is Nothing Then
Set rngCopy = shtImport.Range(c.Offset(1, 0), _
shtImport.Cells(Rows.Count, c.Column).End(xlUp))
Set rngCopyTo = shtMain.Cells(Rows.Count, _
f.Column).End(xlUp).Offset(1, 0)
'copy values
rngCopyTo.Resize(rngCopy.Rows.Count, 1).Value = rngCopy.Value
End If
End If
Next c
End Sub
Thanks,
Ryan