ClearContents for constants but not formulas - vba

I've got a range (N1:N12) on a sheet1 and I've got a code that copy and paste me the values of that range on a secondary sheet2. Everything is working, anyway i didn't consider that i want another button that clear only values in range N1:N12 once i have copied them in sheet2. I don't know how to keep formulas on that range when i want to delete values. Do you have an idea ? I've already tried a normal macro that deletes everything but it is not what i want.
Sub Cancella()
Sheets("Foglio1").select
Range("N1:N12").clearcontents
End Sub
The code i use for copying
Dim lastRow As Long
Sheets("Training Analysis").Range("P1:R13").Copy
lastRow = Sheets("Foglio1").Range("a65536").End(xlUp).Row
Sheets("Foglio1").Range("A" & lastRow + 1).PasteSpecial Paste:=xlPasteValues, Transpose:=True

Replace:
Range("N1:N12").clearcontents
with:
For i = 1 To 12
If Not Cells(i, "N").HasFormula Then Cells(i, "N").ClearContents
Next i

There is a subset of the Range.SpecialCells method that targets xlCellTypeConstants. This can be further broken down to xlNumbers, xlTextValues, xlErrors , xlLogical or a combination of same.
With WorkSheets("Foglio1")
.Range("N1:N12").SpecialCells(xlCellTypeConstants, xlNumbers).ClearContents
End With
Conversely, cells containing formulas can be similarly targeted with the xlCellTypeFormulas subset.

Related

Cut and paste values from sheet 1 to the next available row on sheet 2

I am trying to cut and past values from a range of cells on sheet 1 to the next available row on sheet 2. All guides and advice I've seen has been for copying and pasting and for same sheet.
Range on sheet 1 is E5-H5 to be cut, not copied, and then pasted to sheet 2, cells E7-H7 or the next available row below that as each time someone enters data I need sheet 2 to keep it.
Don't select. I post this answer more to help #KoderM16 improve their methods than to answer the original question:
Sub CutPaste()
ThisWorkbook.Sheets("Sheet1").Range("E5:H5").Copy
Sheets("Sheet2").Cells(Rows.Count, 5).End(xlUp).Offset(1, 0).PasteSpecial
End Sub
Also this doesn't make sense as it returns true or false (will most likely always be true because it can in fact select that address):
Lastrow = Sheets("Sheet2").Cells(Rows.Count, 5).End(xlUp).Offset(1, 0).Select
You would want .row on the end instead of .select if you want to assign the row to Lastrow, you don't however then use lastrow.
With your code as it is, lastrow would most likely always be -1 as that is the value for True
The below code will copy your range and look for the 1st empty cell (from the bottom up) in column E, Sheet 2, to paste. Hope this helps.
Sub CutPaste()
Dim Lastrow As Long
ThisWorkbook.Sheets("Sheet1").Range("E5:H5").Copy
Lastrow = Sheets("Sheet2").Cells(Rows.Count, 5).End(xlUp).Offset(1, 0).Select
Selection.PasteSpecial
End Sub
As you are new to Stack Overflow and probably vba as well, just try to adhere to the comment above by Peh. Your question, while not specifically, is easily googlable in parts. Also, if this answers your question, please tick it.

Trying to copy a formula down an entire column to the last row of data in an adjacent column

I am a new VBA user, and I am trying to create a VBA code to copy a single Vlookup formula down an entire column to the last row of data in an adjacent column. I don't want to specify a specific range, because I intend to use this macro with multiple different files that have different row ranges, so I am looking for a code that will simply copy down to the last value in an adjacent column.
I have tried looking at other similar questions and answers on this website, but none of the solutions that I have found have been working, and I would really appreciate some help!
Here is my code that I currently have:
' Section5 Macro
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[6],'[PERSONAL.XLSB]Task and Sections'!R2C1:R254C2,2,FALSE)"
Range("C2").Select
Selection.Copy 'Copy Vlookup Formula
Dim lastRow As Long
lastRow = Range("B" & Rows.Count).End(xlUp).Row
Range("C3").AutoFill destination:=Range("C3:C" & lastRow) 'Specify range for Column C based off of row count in Column B
Application.CutCopyMode = False
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False 'Paste Vlookup equation down the column
End Sub
The formula I want to copy is "=VLOOKUP(RC[6],'[PERSONAL.XLSB]Task and Sections'!R2C1:R254C2,2,FALSE". The column that I want to copy this formula down is column C (in all rows except C1 which is the Header). The column that I want to refer to for row length is the adjacent column B.
Currently I am getting an error that says "Compile error: Named argument not found".
Any help would be greatly appreciated!
Thank you,
As pointed in the comment, you had a simple typo ("desination")... Nevertheless, your code doesn't seem to work even when this is fixed.
There's a much simpler approach. Try this:
Sub FillWithFormula()
Dim lastRow As Long
lastRow = Range("B" & Rows.Count).End(xlUp).Row
Range("C2:C" & lastRow).FormulaLocal = "=B2*2"
End Sub
Notice that I replaced your formula with a simpler one (independent of external data) so I could verify that the routine works.
Here.
Sub thing()
Dim lastRow As Long
lastRow = Cells(Rows.Count, 2).End(xlUp).Row
Range("C3:C" & lastRow).FormulaR1C1 = "=VLOOKUP(RC[6],'[PERSONAL.XLSB]Task and Sections'!R2C1:R254C2,2,FALSE)"
Range("C3:C" & lastRow).Value = Range("C3:C" & lastRow).Value
End Sub
Simpler, more elegant. Hasn't this kind of thing been solved like a million times all around the internet? Anyway, copy-paste is the slowest thing you can do in a macro. Avoid it. Just set the values of a range to be the values of the range. :)
Also, you can assign a formula to a whole range.

VBA code in Excel to add a row to multiple sheets and then copy formula from adjacent row

I'm really hoping someone can help me with this one. I have recorded a macro to use within a sheet that needs to create a row at the same position on 2 worksheets and then, on one of them, copy the formula's in the cells from the row below it. The code I have looks like this -
Sub Macro1()
Sheets(Array("SCHEDULE", "ANNUAL SUMMARY")).Select
Sheets("SCHEDULE").Activate
ActiveCell.Offset(1, 0).Rows("1:1").EntireRow.Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Sheets("ANNUAL SUMMARY").Select
ActiveCell.Offset(1, 0).Rows("1:1").EntireRow.Select
Selection.AutoFill Destination:=ActiveCell.Offset(-1, 0).Rows("1:2").EntireRow _
, Type:=xlFillDefault
ActiveCell.Offset(-1, 0).Rows("1:2").EntireRow.Select
Sheets("SCHEDULE").Select
ActiveCell.Select
My problem is, when I run it manually and then record the macro, it does exactly what I want it to, but when I run this from a button on the "SCHEDULE" sheet it does not copy the formula's from the row below the one on the "ANNUAL SUMMARY" sheet.
Can anyone help to get this working with me?
Thanks all in advance
Mark
The problem with the macro recorder is that although it can give you a good indication of what code you need, it also generates very inefficient code and includes all of the select and activate statements that you need to try and avoid using.
Any reference in the code to ActiveCell is referring to the cell that is currently selected and ActiveSheet is the sheet that is currently selected. This can give you undesired results if you run the macro from a different sheet that the macro was recorded from...
If you wanted to copy row 1 from SCHEDULE sheet then you can use
Sheets("SCHEDULE").Rows(1).Copy Sheets("ANNUAL SUMMARY").Rows(1)
If you want to auto fill a range, then this can be accomplished with a single line of code
This will auto fill the contents of row1 (column A - E) down to row 100 in your ANNUAL SUMMARY sheet
Sheets("ANNUAL SUMMARY").Range("A1:E100").FillDown
So if we put it all together and include some declarations for our source and destination sheet to make the sub more readable..
Sub CopyAndFillDownExample()
Dim rowNumber As Long, offset As Long
Dim sourceSht As Worksheet, destinationSht As Worksheet
'set the source and destinationsheets
Set sourceSht = Sheets("SCHEDULE")
Set destinationSht = Sheets("ANNUAL SUMMARY")
'number of rows to copy down
offset = 100
'get currently selected row
rowNumber = ActiveCell.Row
'copy the selected row from the source sheet to the destination sheet
sourceSht.Rows(rowNumber).Copy destinationSht.Rows(rowNumber)
'fill down the formulas
destinationSht.Rows(rowNumber & ":" & rowNumber + offset).FillDown
End Sub

Looking to select an undetermined number of rows in excel as part of larger VBA macro

I'm working with an excel book containing a large number of sheets; the first sheet is linked to an external program and pulls in data via an external function, and the number of lines imported varies significantly.
This block data is the disseminated over a number of subsequent sheets. The first step has been to populate column A (row name) with the number of rows in sheet 1. From here the data is split over a number of columns (currently B->L). The top row uses an IF() function to populate the first row, and I'm looking to write a clean macro to copy this formula to row x (which varies with each data import refresh) and then paste values for a manageable file size.
Here's what I've got so far; it works, but it's fairly (read: VERY!) clumsy:
Sub Refresh_Data()
Sheets("Sheet2").Select
ActiveWindow.ScrollWorkbookTabs Sheets:=13
Sheets(Array("Sheet2" ... "Sheet25")).Select
Sheets("Sheet2").Activate
Sheets("Sheet25").Select Replace:=False
Range("B1:L1").Select
Selection.Copy
Range("__B2:B1000__").Select
ActiveSheet.Paste
Application.Calculate
ActiveWindow.ScrollWorkbookTabs Position:=xlFirst
Sheets(Array("Sheet2" ... "Sheet25")).Select
Sheets("Sheet2").Activate
Sheets("Sheet25").Select Replace:=False
Sheets("Sheet2").Select
Range("B3").Select
Sheets(Array("Sheet2" ... "Sheet25")).Select
Sheets("Sheet2").Activate
Sheets("Sheet25").Select Replace:=False
Range("B3:L4").Select
Range("__B2:L1000__").Select
Application.CutCopyMode = False
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("Check_sheet").Select
MsgBox "Update complete"
End Sub`
The main thing I'm looking to achieve is to replace the code B2:L1000 with something that can assess the number of rows in column A and select a range in rows B to L accordingly.
Since column L is the last populated column, I don't see why this can't also be done horizontally rather than defining "B:L" incase future columns need to be added.
Although the earlier answer has merits:
1) I would not use COUNTA because if there are empty cells in the row or column, the cells at the bottom or the right will be ignored.
2) I would never rely on the user picking the correct sheet to be used before running a macro; particularly one with so many sheets.
My reaction to the question is that you have set Macro Record, wandered around your workbook and then stopped the record. You select one thing, then another. You scroll through the sheets. To me most of the statements are not clumsy they are pointless.
The following does include an answer to your question about finding the last row of column A but it is more a tutorial about finding the dimensions of a range, getting data out of the range and then putting it somewhere else. This seems to be most of what you are trying to do with the most minimal understanding of VBA. I am sorry if this criticism is unfair but that is the impression your question gives to me.
Sub Test()
Dim RowS01Max As Integer
Dim Sheet1Data() As Variant
' With Sheets("Sheet1") allows you to access data within worksheet Sheet1
' without selecting it.
' Range("A1:C11") refers to a range within the active sheet
' .Range("A1:C11") refers to a range within the sheet identified in the
' With statement.
' ^ Note the dot
With Sheets("Sheet1")
' Rows.Count is the number of rows for the version of Excel you are using.
' .Cells(Rows.Count, "A") address the bottom row of column A of worksheet
' Sheet1.
' .Cells(Rows.Count, 1) refer to column A by number.
' End(xlUp) is the VBA equivalent of Ctrl+Up.
' If you positioned the cursor at the bottom of column A and pressed
' Ctrl+Up, the cursor would jump to the last row in column A with a value.
' The following statement gets that row number without actually moving
' the cursor.
RowS01Max = .Cells(Rows.Count, "A").End(xlUp)
' The following statement loads the contents of range A1:C11 of
' Sheets("Sheet1") into array Sheet1Data.
Sheet1Data = .Range("A1:C11").Value
' This is the same statement but the range is specified in a different way.
' .Cells(Row,Column) identifies a single cell within the sheet specified in
' the With statement. .Cells(1,1) identifies row 1, column 1 which is A1.
'. Cells(11, "C") identifies row 11, column C which is C11.
Sheet1Data = .Range(.Cells(1, 1), .Cells(11, "C")).Value
' This statement uses RowS01Max to specify the last row
Sheet1Data = .Range(.Cells(1, 1), .Cells(RowS01Max, 1)).Value
' In all three examples above, the contents of the specified range will
' be loaded to array Sheet1Data. Whichever range you pick, Sheet1Data
' will always be a two dimensional array with the first dimension being
' the row and the second dimension being the column.
' In the first two examples Sheet1Data(5,3) contains the contents
' of cell C5. In the third example, I have only loaded column A but the
' array will still has two dimensions but the only permitted value for the
' second dimension is 1.
' The following statement writes the contents of Sheet1Data to column "E"
.Range(.Cells(1, 5), .Cells(RowS01Max, 5)).Value = Sheet1Data
End With
With Sheets("Sheet2")
' The following statement writes the contents of Sheet1Data to column "E"
' of worksheet Sheet2.
.Range(.Cells(1, 5), .Cells(RowS01Max, 5)).Value = Sheet1Data
End With
End Sub
Don't despair! Most of us started with the macro recorder and still use it to discover the syntax for an unfamiliar command. Look through other questions. Some ask about exotic functionality but many are about moving data around in, to the experienced programmer, simple ways. Set up some workbooks with the questioner's problem. Copy and paste the solution into a module. Step through it using F8 (see the debugger), switch between Excel and Editor, watch what is happening to the worksheet and move the cursor over a variable to see its current value. Spend half a day playing. You will be amazed at how quickly it starts to make sense. Good luck and good programming.
The following should do the trick:
Sub Refresh_Data()
Dim lastRow As Integer
Dim lastCol As Integer
Dim entireRange As Range
Dim targetRange As Range
lastRow = Excel.Evaluate("COUNTA(A:A)") ''// count the rows in column A
lastCol = Excel.Evaluate("COUNTA(1:1)") ''// count the columns in row 1
Set entireRange = Range(Cells(1, 2), Cells(lastRow, lastCol))
Set targetRange = Range(Cells(2, 2), Cells(lastRow, lastCol))
entireRange.FillDown
Application.Calculate
targetRange.Copy
targetRange.PasteSpecial Paste:=xlPasteValues
End Sub
Notes:
Excel.Evaluate(...) allows you to use the result of worksheet functions in your VBA macros.
COUNTA(range) is a worksheet function that counts the number of non-blank cells in a given range. In this case, it can be used to determine the total number of rows in your data set, as well as the number of columns in row 1 that have a formula in them.

Excel Macro: make a recorded one less cell specifc?

I've recorded a simple macro that I need to make into something generic, so it can be used for any row and last four cells. Here is my recroded version:
Selection.End(xlToRight).Select
Selection.End(xlToRight).Select
Selection.End(xlToRight).Select
Selection.End(xlToRight).Select
Selection.End(xlToLeft).Select
Range("Q12:T12").Select
Range("T12").Activate
Selection.Copy
End Sub
How do I
make it go to the last cell of the ROW I place the cursor into?
change the cell specific ranges into a range that just means: select this cell and 3 more to the left?
... the selection.copy I think I can nearly manage :)
Many thanks
Mike
This will copy the last four cells in any row you click into:
Sub CopyLastFourCellsOfRow()
Dim lastCell As Range
Dim rngToCopy As Range
Set lastCell = Selection.End(xlToRight)
Set rngToCopy = Range(lastCell, lastCell.Offset(0, -3))
rngToCopy.Copy
End Sub
Update - If your row has broken data then best approach is to start in the final column of the spreadsheet (column IV) and then work back. To achieve this replace the lastCell statement with the following:
Set lastCell = Cells(Selection.Row, 256).End(xlToLeft)
You can actually do the individual steps you're asking about all in one swift move.
To make it go to the last cell in the current row, you just use ActiveCell.End(xlToRight). (Use 'ActiveCell' because it is equivalent to 'Selection' when only one cell is selected, but works even if multiple cells are selected.)
Range(ActiveCell, ActiveCell.Offset(0, -3)).Select
will select the current cell and 3 more to the left. Note that you do not need to do "Selection.Copy" in a separate step. You can simply go:
Range(ActiveCell, ActiveCell.Offset(0, -3)).Copy