Excel VBA - Paste to visible cells - excel

I have a template that's linking to external source.
My predecessor created it and that for 'easiness' on the eye, he/she created it by skipping a row. i.e. row 1 then row 3, row 5, row 9, row 13 etc HAS FORMULA, whereas in between those mentioned rows are just DEFAULT EMPTY CELL.
I've created a vba that opens the workbook and copy the sheet that I want.
If I were to use the code below, it's running very slowly, and for some reason, it loops more than once.
for each cell in usedrange
if cell.hasformula = true and instr(cell.formula, "SUMIF") > 0 then
cell.formulaR1C1 = "='\\tel\folder1\folder2\[xlsheet.xlsx]SheetName'!RC
end if
next cell
Therefore, what I've done is to actually assign it once, copy it and then paste to the respective cells (as shown below).
Workbooks(desWB).Sheets(maxSheet + 1).Range("J5").FormulaR1C1 = fullPath
Workbooks(desWB).Sheets(maxSheet + 1).Range("J5").Copy
Workbooks(desWB).Sheets(maxSheet + 1).Range("J6:J12,E48:J55,E57:J58,E61:J79,E84:J93,E96:J96,E99:J103").PasteSpecial Paste:=xlPasteFormulas
The latter method works and it's definitely much faster than the first. However, now I am facing a situation where due to the setup of the template, some rows have formulas and some doesn't, and it goes to thousands of rows. The skipping of rows too sometimes is not an increment of 2, it could be 3, 5 etc.
So am wondering if there's a way that's more effective and efficient to:
Look at the used range
If range has formula AND formula has 'SUMIF'
Change the formula to something else
Else SKIP and check next cell

If you only want to process rows where the first cell in that row has a non-empty cell value then you should iterate the Ranges rows and columns and skip the rows when the first cell fails the test.
Your current code that uses a For Each cell in range approach will still keep processing cells in an empty row - which is redundant.
You can use code like below to skip the blank rows and only apply conditional logic to rows where you are confident that some cells have the formula you want to update. In the example, I use Range("C4:E10") but you can substitute for the Range that works for you depending on your workbook structure.
Option Explicit
Sub Test()
'could pass in UsedRange of the sheet...
IterateRange ThisWorkbook.Worksheets("Sheet1").Range("C4:E10")
End Sub
Sub IterateRange(rng As Range)
Dim rngCell As Range
Dim intX As Integer
Dim intY As Integer
'iterate all cells in range
For intX = 1 To rng.Rows.Count
For intY = 1 To rng.Columns.Count
'get a cell
Set rngCell = rng.Cells(intX, intY)
'check if cell is blank or empty
If IsEmpty(rngCell.Value) Or rngCell.Value = "" Then
'skip the rest of the columns in this row and goto next row
Exit For
Else
'this row has non-empty cells - do something
Debug.Print rngCell.Address
'some other test
If rngCell.HasFormula And InStr(1, rngCell.Formula, "SUMIF") Then
'update formula...
Debug.Print rngCell.Formula
End If
End If
Next intY
Next intX
End Sub

Code line to execute:
Range("A1:A10").SpecialCells(xlCellTypeVisible).Value = "1"
'This line send 1 to Visible Cells in A1:A10 range

Related

Apply formula to all visible cells in column CK, occasionally there will be no rows

I have a filter applied to column CK, I am able to select the next visible row from the header by using the following, which also applies a formula into that active cell.
How do I fill that formula down to the bottom, without affecting the hidden rows?
Occasionally there will be no data, so it's just applying a formula to a blank row..
range("CK1").Select
ActiveSheet.range("$A$1").AutoFilter Field:=89, Criteria1:="0"
' Add if formula to find missing carriers based on patterns
Do
ActiveCell.Offset(1, 0).Select
Loop While ActiveCell.EntireRow.Hidden = True
ActiveCell.Formula2R1C1 = _
"=IFS(AND(LEN(RC[1])=18,LEFT(RC[1],2)=""1Z""), ""UPS"", AND(LEN(RC[1])=12,ISNUMBER(RC[1])),""FedEx"",AND(LEN(RC[1])=10,ISNUMBER(RC[1])),""DHL"",AND(LEN(RC[1])=11,LEFT(RC[1],2)=""06""),
It would be great if you could refrain from selecting cells or activating sheets or workbooks like you do. The only time it is fine to have Excel change its selection on screen with VBA is if you want it to.
For your problem, a simple loop will do. Example with CK1 and all the cells below it:
Dim topCell As Range, bottomCell As Range
Set topCell = Range("CK1")
Set bottomCell = topCell.end(xlDown)
'Next test is optional, although recommended (is there no cell filled under CK1?)
If bottomCell.Row >= 1048576 Then 'Current maximal row; you may change the threshold if desired.
Exit Sub
'Alternatively: Exit Function
'Other alternative example: Set bottomCell = Range("CK1000")
End If
Dim c As Range
For Each c In Range(topCell, bottomCell)
If Not c.EntireRow.Hidden Then
c.Formula2R1C1 = "" '<place your formula here>
End If
Next c

Excel VBA: How to clear contents for specified cells when another cell contains specific text or string

I'm having some trouble trying to find VBA code to delete multiple specific cells if a certain cell contains a specific text. This spreadsheet can run close to 100k rows as well, but will vary depending on the data pull.
The specific VBA would be able to do the following:
If Cell J3 equals #N/A, Blank, or 0, then clear contents of cells J3:K3 and P3:X3, and then repeat til it reaches the bottom of column J.
Thanks in advance
How to clear contents for specified cells when another cell contains specific text or string
Dim cellToClear As Range
Dim cellToCheck As Range
Dim specificText As String
If cellToCheck.Value = specificText Then cellToClear.ClearContents
"I'm having some trouble trying to find VBA code "
These links contain VBA code that you can use when you no longer have trouble trying. They contain examples you can paste into your project and modify for your needs.
This link has examples of how to read the contents of a cell.
A range is a group of one or more cells in a worksheet. You can perform an operation on a range and it will affect all the cells inside the range. This link has examples of how to work with a range.
A loop is when the program repeats the same sequence of steps, usually until a specific condition is met. You can find examples of different loops here.
I prefer placing values into an array if you are going to be changing a bunch of cells in a routine. This generally makes the process much quicker.
Start out by setting your worksheet and range objects. Please take note that the below code is currently using index 1 for the worksheet here: Set ws = ThisWorkbook.Worksheets(1). If this is not the worksheet you are personally needing, then you will need to change this.
Then place the cell contents of the entire range into an array. As I mentioned earlier, this process is quicker than making adjustments to individual cells 1 at a time.
Loop the array, checking for either the specific error value #N/A or the other criteria. If this criteria is a match, you will enter another loop that quickly loops through the 'columns' in the row that will delete the values from only the columns you specified.
Once finished, rewrite the array back to the worksheet.
Sub main()
Dim ws As Worksheet, rng As Range, dataArr() As Variant
Set ws = ThisWorkbook.Worksheets(1)
Set rng = ws.Range("J3:X" & ws.Cells(ws.Rows.Count, "J").End(xlUp).Row)
' Place the entire contents of worksheet range into an array
dataArr = rng.Value
Dim i As Long, x As Long, clearRow As Boolean
For i = LBound(dataArr) To UBound(dataArr)
If IsError(dataArr(i, 1)) Then
If dataArr(i, 1) = CVErr(xlErrNA) Then clearRow = True
ElseIf dataArr(i, 1) = vbNullString Or dataArr(i, 1) = 0 Then
clearRow = True
End If
' Loop thru the columns (x) of the current row (i)
If clearRow Then
For x = 1 To 15
Select Case x
Case 1, 2, 7 To 15
dataArr(i, x) = ""
End Select
Next x
clearRow = False
End If
Next i
' Re-write the entire array back to the worksheet in one step
rng.Value = dataArr
End Sub

My nested For-Each loop isn't going through each cell in a given range

In Excel VBA:
My second For-Each loop is only going through the first cell in a given column.
I need help getting it to go through each cell in the entire column.
In my code included here, I want to loop through each cell in a row (no issue). then once a cell in the row matches my criteria (no issue), I want to loop through each cell (celltwo) in that cell's column (issue).
I'm able to loop through the row and identify my criteria, but then the second for-each loop only considers the first celltwo in the given column. So I never get a celltwo with .row >=10, the first cell in each column has row=1.
Any help is appreciated.
This is for VBA in Excel. I've tried different ways of identifying my second range to loop through but nothing has allowed the second for-each loop to cycle back from "Next Celltwo" to the beginning of the loop.
Sub WriteSummary()
Dim UploadRange As Range
Dim SummaryRow As Integer
Dim CategoryRange As Range
Dim Cell As Range
Dim Celltwo As Range
''''''''''''''''''''''''''''''''''''''''''''''''''''
'Set Variables
Set MacroFile = ThisWorkbook
Set MacroSheet = ThisWorkbook.Worksheets("Macro")
Set UploadDash = ThisWorkbook.Worksheets("Upload Dash")
Set SummarySheet = ThisWorkbook.Worksheets("Summary")
Set IndexSheet = ThisWorkbook.Worksheets("Indexes")
Set CategoryRange = UploadDash.Range("5:5")
''''''''''''''''''''''''''''''''''''''''''''''''''''
'Determine Output Row
SummaryRow = SummarySheet.Cells(Rows.Count, 1).End(xlUp).Row + 1
''''''MY PROBLEM STARTS HERE'''''''
For Each Cell In CategoryRange
If Cell.Value = 8840 Then
For Each Celltwo In SummarySheet.Cells(, Cell.Column).EntireColumn
i = MsgBox(Celltwo.Row, vbOKOnly)
If Celltwo.Row >= 10 Then
If Celltwo.Value > 0 Then
o = MsgBox(Celltwo.AddressLocal)
SummaryRow = SummaryRow + 1
Else
End If
Else
End If
Next Celltwo '''''DOES NOT LOOP'''''
Else
End If
Next Cell
I expect that when the code finds cell.value = 8840 it will then loop through each cell in that cell's column. Instead, it only loops through the first cell in that column and exits the second for-each loop
Cells needs a row and column argument, but I think it's the EntireColumn which is taking the whole column as a single range.
Try something like this instead, which will restrict to cells containing something.
It starts at row 6 so amend to suit.
With SummarySheet
For Each Celltwo In .Range(.Cells(6, Cell.Column), .Cells(.Rows.Count, Cell.Column).end(xlup))
' etc
Next
End With

Delete entire row if cells in specific range are all empty

I want to create a macro that would delete an entire row if all the cells in specific range (B to K in each of the 10 rows) are all empty. I tried the following:
Dim i As Integer
Dim rng As Range
For i = 1 To 10
Set rng = Range("B" & i, "K" & i).SpecialCells(xlCellTypeBlanks)
rng.EntireRow.Delete
Next i
If there are more following lines with empty cells, let's say 1 and 2, it deletes row 1 and move row 2 instead of the deleted one, so it becomes row 1. Then it skips the moved row, because i always increases so it never checks row 1 again. Is there any way to check if the row that was just deleted is really non-empty before moving to the next i?
Btw: I am using Excel 2013.
Instead of using the Special Cells, why not just use CountA()?
Sub t()
Dim i&
For i = 10 To 1 Step -1
If WorksheetFunction.CountA(Range("B" & i, "K" & i)) = 0 Then
Rows(i).EntireRow.Delete
End If
Next i
End Sub
That way, you can avoid any errors in case there's no blanks. Also, when deleting rows, it's recommended to start at the end, then Step -1 to the beginning.
Edit:
Try this as well, it may be quicker:
Sub T()
Dim rng As Range
Set rng = Range("B1:K10") ' Since you're going to loop through row 1 to 10, just grab the blank cells from the start
rng.SpecialCells(xlCellTypeBlanks).EntireRow.Select ' Just to show you what's being selected. Comment this out in the final code
rng.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End Sub
I recommend stepping through that with F8 first, to see how it works. In the range B1:K10, it will first select all rows where there's a blank cell. Then, it'll delete those rows.

Select non-blank rows in spreadsheet

I am going to try and keep this as short as I can and still explain adequately, here goes :)
I have searched forums, my VBA literature, and cannot find a way to do what I'm trying.
I have a spreadsheet with rowTotal >= 60 rows. The rows either have text data in cells of each column, or the rows are blank with a pattern and colorindex set.
I need a macro to select all non-blank rows.
I first tried looping through the cells of column A (if a cell in column A has text data, then its row should be selected), checking if activecell.value <> empty.
Here's the jist (mix of pseudocode & code):
Range("A1").Select
loop to end
if activeCell.value <> empty then
stringVar = stringVar + cstr(activeCell.row) + ":" + cstr(activeCell.row) + ","
end if
end loop
stringVar = Left(stringVar, (Len(stringVar) - 1))
Range(stringVar).Select
If I have total 10 rows with rows 2 and 8 having data, stringVar would resolve to this: "2:2, 8:8".
Range(stringVar).Select would have same result as writing Range("2:2, 8:8").Select.
If the number of rows to be in the range is <= 45, this works no problem. However, as soon as the number of rows with data in them exceeds 45, the code fails on Range(stringVar).Select.
I tried the macro recorder and it gets around this by using the Union method. And so I thought, "self, you can get this done with Union(). hooray MacroRecorder." But alas, my joy was remiss.
I was thinking I could split the one large string into 1 or more strings; each of these smaller strings would be under the 45 limit mentioned above. Then I can use Union() to group all the ranges (these smaller strings) together into the one desired range.
However, I would have to "build" my Union() code in real time during code execution, after I knew how many of these 45> strings I had.
Anyone know how to take a worksheet and select just rows that contain data; which amounts to having a range of non-contiguous rows where more than a count of 45 rows are selected.
No need for loops - use SpecialCells
For column A only use:
Set rng1 = Columns("A").SpecialCells(xlCellTypeConstants).EntireRow
instead.
Sub QuickSet()
Dim rng1 As Range
On Error Resume Next
Set rng1 = Cells.SpecialCells(xlCellTypeConstants).EntireRow
On Error GoTo 0
If Not rng1 Is Nothing Then
MsgBox "Your working range is " & rng1.Address(0, 0)
Else
MsgBox "No constants found"
End If
End Sub
I first suggest you try using Autofilter. If you're using Excel 2010 (and prob 2007, but I can't check) this is as simple as selecting your data, choosing the "Data" tab, then clicking Filter. Using the drop-down box in your first column, deselect "blanks".
The exact same functionality exists in Excel 2003, under the Data/Filter menu option. I can't really remember it all that well, though; you'll have to experiment, or Google it.
If that doesn't work:
Sub it()
Dim cell As Range
Dim selectRange As Range
For Each cell In ActiveSheet.Range("A:A")
If (cell.Value <> "") Then
If selectRange Is Nothing Then
Set selectRange = cell
Else
Set selectRange = Union(cell, selectRange)
End If
End If
Next cell
selectRange.Select
' selectRange.EntireRow.Select 'If you want to select entire rows
End Sub
Just used this code and it worked a treat - been tracking all other excel forums but couldn't find anything that was as simplified.
I also added that the selected rows were copied and pasted to the next blank row in another sheet, if anyone finds this useful.
Sub copypaste1()
'Find rows that contain any value in column A and copy them
Dim cell As Range
Dim selectRange As Range
For Each cell In ActiveSheet.Range("A:A")
If (cell.Value <> "") Then
If selectRange Is Nothing Then
Set selectRange = cell
Else
Set selectRange = Union(cell, selectRange)
End If
End If
Next cell
selectRange.EntireRow.Select
selectRange.EntireRow.Copy
'Paste copied selection to the worksheet 'mega' on the next blank row
Sheets("mega").Range("A65536").End(xlUp).Offset(1, 0).PasteSpecial _
Paste:=xlPasteValues
End Sub

Resources