Visual Basic use of EntireRow.Copy starting from a specific column - excel

I would like to copy entire rows from mutliple sheets to a target sheet.
But I would like to start the row copy from column B of the target sheet.
I tried
Sheet1.Range("13:32").EntireRow.Copy Sheet5.Range("2:21")
that works fine but starts from column A of target sheet, sheet5 ;
I then tried
Sheet1.Range("13:32").EntireRow.Copy Sheet5.Range("B2:21")
but gives an error.
Can you please help?
Thanks a lot,
Electra

EntireRow will always return ... well ... the entire row!
Therefore you receive an error on the second row - as there are too many cells to be inserted.
You have to resize the range using this function - it will reduce the range by one column and then offsets it to start at the second column.
Public Function resizeRowToStartFromColumnB(rg As Range) As Range
Dim rgResized As Range
With rg
Set rgResized = .Resize(, .Columns.Count - 1).Offset(, 1)
End With
Set resizeRowToStartFromColumnB = rgResized
End Function
Within your code you could use it like:
resizeRowToStartFromColumnB(Sheet1.Range("13:32")).Copy Sheet5.Range("B2")

Related

Getting Specified Column of an Excel Table as a Range

I have a table named table in a worksheet titled Sheet. I want to get a range consisting of the a specified column of the body of the table. The following code works:
Public Function GetColumn(colNum as Integer) As Range
With Sheet.ListObjects("table").DataBodyRange
Set GetColumn = Range(.Cells(1, colNum), .Cells(.Rows.Count, colNum))
End With
End Function
I feel there must be a more elegant way to solve this problem.
It seemed like the Columns property would be the way to go but I can't seem to get the syntax right.
You can use the Columns-property of a range to get the range for one column of that range simply by specifying the column number. Note that the index is always relative, if your range starts at C3, column(2) would refer to column D of the sheet.
So for you case:
Including the header cell:
Set GetColumn = ws.ListObjects("Table").Range.Columns(colNum)
Without header cell:
Set GetColumn = ws.ListObjects("Table").DataBodyRange.Columns(colNum)
Update: When you access a Range like that and iterate over it with foreach, it will only execute one iteration, containing all cells. Fix is easy:
Set GetColumn = ws.ListObjects("Table").DataBodyRange.Columns(colNum).Cells

Selecting Only Columns Within Range

I am trying to write a macro which only calls a function for every third cell within a range.
Currently I have the following:
Sub CallFormula()
Dim rng As Range
Set rng = Range("startcell:end:cell")
With rng
For i = Range.Columns("G13") To Range.Columns("endcell")
Columns(i).SpecialCells(xlCellTypeFormulas).Select
Call formula()
Next i
End With
End Sub()
The range starts with startcell and ends with endcell and is basically a rectangle. I want to loop through every column starting from column G (which is the 2nd column after startcell).
The problem is that I only want to call the function on rows within this range. However, the function is executed on all cells that have a formula in every third column after column G. I thought using With would fix it, but it does not.
Any solutions?
Thank you!

How can I copy and insert into a named range that contains merged cells using VBA?

I would like to have a subroutine that is passed a named range and a number of rows, and copies that number of rows from the bottom of the range and inserts them into the named range at the bottom, becoming the new bottom of the named range. If I have a range named 'WellC1', depicted here:
I would like the function to copy the bottom n rows (in this case, 12) and paste them (or insert them) at the bottom, while keeping them within the named range, so it ends up like this:
It should only paste the formulas (which is what is shown here as the 11.47 and numbers on the right are formula results) and needs to copy within the named range so the process can be repeated.
Im new to VBA and having severa problems with this. One is insert adds things above the insert point; to keep the new years' data in the named range I figured I could add the first row of the next well's data to the bottom of the range and insert there (so top row of Well C2 is actually the bottom row of Well C1s named range and inserting at it keeps the new Well C1 data in the well C1 range). I can get the insert-into-named-range thing to work fine if there's no merged cells, btw.
The other is I can't figure out how to actually copy the 12 (or n) bottom rows of named range WellC1, because of the merged cells. Is there a way to copy the bottom n rows of a range and/or reference them even if some are merged? What I've been trying so far is tweaking out versions of this:
Sub Copy_Insert_Into_Named_Range( _
target_range As Range, _
Optional num_rows As Integer = 1)
'This uses the top row of the next well range as the bottom of this named range to be able to use a copy/insert and keep it within the named range.
Dim last_row As Range: Set last_row = target_range.Rows((target_range.Rows.Count) - 1)
Dim top_row As Range: Set top_row = target_range.Rows((target_range.Rows.Count) - (num_rows + 1))
Dim num_targ_columns As Integer: num_targ_columns = target_range.Columns.Count
Dim upper_cell As Range: Set upper_cell = top_row.Cells(1)
Dim lower_cell As Range: Set lower_cell = last_row.Cells(num_targ_columns)
Dim copy_area As Range: Set copy_area = Range(upper_cell & ":" & lower_cell)
copy_area.Copy
last_row.Offset(1).PasteSpecial
I'm falling apart at the copy_area set, I think because of the merged cell being lower_cell. Is there a different way to select these 12 (or n) bottom rows of the named range? There's about 600 of these wells we do this to manually per project so I'd like to automate that. My core idea is have each well's area be a named range and step through each named range and run the copy/insert function for it. Its working in other projects that don't have merged cells. I appreciate any ideas!

Is it possible to select a range of data via a macro if the start and end row is variable?

I need to add a piece of code to my macro that copies and pastes a range of data.
The problem that I am having is that the data can start and finish on any row.
Is it possible to do this?
e.g. Currently the data starts in cell C10 and ends in cell I20. But next month it could start in C5 and end in I40.
The column range will always remain the same i.e C:I, but the row will change each time.
How to a add code to search for the first instance of data in Column C and copy all the data that follows?
Thanks
Here are some code snippets that might help
Get the first cell in C
If Range("C1").Value <> "" Then
Set firstcell = Range("C1")
Else
Set firstcell = Range("C1").End(xlDown)
End If
I test C1 because it will go all the way to the bottom if that is the only cell in C with values.
After that, to get the bottom cell after that
Set lastcell = Cells(Rows.Count, "I").End(xlUp)
Another way might be to use a named range in the spreadsheet to define the range you want to copy.
=OFFSET(C1,MATCH(TRUE,INDEX(NOT(ISBLANK(C:C)),0),0)-1,0,COUNTA(C:C),7)
That formula will select any number of data rows starting anywhere in column C. It doesn't account for header rows or any other content. If your data would always start in at least, say, row 5, then you could adjust the C1 value and use C5:C1000 instead of C:C. Then, in the VBA you can just use Range("namedRange"). Copy instead of having to work out the start and end points.
If you highlight the required cells before running the macro, then you can use
Selection
to refer to the selected range
ie, instead of
Range("C10:i20").Clear
you can write
Selection.Clear

PasteSpecial SkipBlanks:=True fails with merged cells

Range1.Copy
Range2.PasteSpecial Paste:=xlPasteFormulas, SkipBlanks:=True
If Range1 and Range2 have the same dimensions, this code executes without any trouble. The expectation is that the formulas in the range you copied will get inserted into the target range, but any blank cells in Range1 will not have their formulas copied to Range2, instead, any current cell values will be left as they were.
I've discovered that this fails on merged cells. The image below demonstrates the equivalent action using the built in Paste Special UI, which fails in an identical fashion:
Can anyone think of an elegant workaround that doesn't involve looping?
Note that simply using a variant of Range1.Formula = Range2.Formula won't suffice since it will overwrite unwanted cells in Range2 with blank (empty) values.
I've removed the no loops restriction because there doesn't seem to be a perfect solution otherwise.
The following was tested and seems to work.
Assumptions:
The first row cells in your post are A1:E1.
The green highlighted row cells in your post are A2:E2.
The range that needs to be partially overwritten is in row 4 (A4:E4).
I have replicated the contents of cells A2:E2 all the way till cell Q2. SoF2:G2 are merged & blank, H2 is blank, I2 has "copy", and so on till Q2 (which has "copy"). I just wanted to make sure that the method works with multiple merged areas.
Sub skipBlanksWithMergedCells()
Dim rngOrigin As Range, rngDestination As Range, rngSkip As Range
Dim varTemp As Variant
Set rngOrigin = Range("A2:Q2")
Set rngDestination = Range("A4:Q4")
' Set pointer to range that needs to be skipped
Set rngSkip = rngOrigin.SpecialCells(xlCellTypeBlanks).Offset(2, 0)
' Store its values into a variant
varTemp = rngSkip.Value
rngOrigin.Copy
rngDestination.PasteSpecial xlPasteFormulas
' Revert original values from the variant
rngSkip.Value = varTemp
End Sub
This will work if rngSkip contains hard numbers or text, but it will fail if it contain formulas.. In that case, we need to set a pointer to the subrange of formulas and store them in another variant, using varTempFormulas=range.formula and then back again range.formula=varTempFormulas.
I hope this helps.
Based on the conclusion that this bug makes it impossible to do this without looping, I've come up with the following solution which I believe to be as elegant as possible with looping.
Dim col as Long
Dim cel as Range
For Each cel In src.Cells
If cel.Formula <> vbNullString Then
col = 1 + src.Column - cel.Column
cel.Copy
dst.Worksheet.Range(dst.Cells(1, col ), dst.Cells(dst.rows, col )).PasteSpecial Paste:=xlPasteFormulas
End If
Next cel
This lets you copy one row of data from a range src and paste formulas over multiple rows in a range dst with only one loop over the columns, while skipping blank. This method never overwrites any destination that should be left alone, so it works in all my use cases.
In a more complex situation where the source data had multiple rows as well as columns, this routine wouldn't work, and I imagine at least 2 levels of nested loops would be required.
Brute Force method:
I had this problem and used this solution.
Copy format for whole page to new temporary page.
Un-merge your page. Do your copy with skip blanks.
Copy format from temporary page to old page.
Delete temporary page.

Resources