So I have a big excel sheet with a bunch of empty cells in various locations. I want an easy to work with list of which cells are empty. I was hoping to make a new worksheet that was populated with the locations of the empty cells. I wanted to have this to just populate the cells I want it to. I kept the header from the worksheet I will be checking and added a blank cells count, so I want the following cells in the column to be populated by the list of empty cell locations.
Now I know I can use =ISBLANK to test if a cell is empty or not, but I only care about the cells that return TRUE. So I figure I'll need a loop. And I want the location of the cell so I can use =CELL. And to make this most readable I want to do this on a column by column basis.
But I want to populate a spreadsheet with this information in a manner similar to how functions work (I just want to copy and paste it to other cells and columns). But it's pretty clear that I am going to need VBA.
My question is how can I create a macro to populate my spreadsheet with a list of empty cells? How do I apply it to the cells?
I assume you have data in sheet1, I have used sample range// Range("A1:c15") however you can define range as per need and blank cells address will be published in next sheet.
Sub FindBlank()
Dim rng As Range
dim i as long
For Each rng In Sheet1.Range("A1:c15").SpecialCells(xlCellTypeBlanks)
i = i + 1
Sheet2.Cells(i, 1) = rng.Address
Next
End Sub
If you want a list of the cells that are empty, you can use Range().SpecialCells(xlCellTypeBlank):
Sub getEmptyCellAddresses()
Dim rng As Range
Dim ws as Worksheet
Set ws = Sheets("Sheet1") ' CHANGE AS NECESSARY
Set rng = ws.Range("A1:A15").SpecialCells(xlCellTypeBlanks) ' Edit/change range as necessary
ws.Cells(1, 2).Value = rng.Cells.Address ' Change `ws.cells(1, 2)` to whatever destination you like
End Sub
Edit: Ah, beaten by 16 seconds by #RamAnuragi ...but anyways, they're slightly different ways to tackle the question so I'll leave it.
Edit: For funsies, here's another way to put them all in a column, one row per cell...and more, per your comments.
Sub listEmptyCells()
Dim emptyAddresses() As String
Dim i As Long
Dim ws As Worksheet
Dim rng As Range
Set ws = Sheets("Sheet1") ' CHANGE AS NECESSARY
Set rng = ws.Range("A1:A15")
If WorksheetFunction.CountBlank(rng) = 0 Then
MsgBox ("No empty cells in the range")
Exit Sub
End If
emptyAddresses() = Split(rng.SpecialCells(xlCellTypeBlanks).Address, ",")
For i = LBound(emptyAddresses) To UBound(emptyAddresses)
ws.Cells(i + 1, 2).Value = emptyAddresses(i)
Next i
End Sub
Related
So first of all, I wanna write a VBA Code, which allows me to pick a certain range of an Excel sheet, to then copy SOME of the needed values to another worksheet. The issue with this is, that in the Excel sheet of which i take Information from, has some filters applied.
So i found the solution with the method (?) .SpecialCells(xlCellTypeVisible) but the Problem again is, that it works for 1 column, but not for Ranges with more than one column. For Ranges with more than one column, it only picks the first row
Dim rng As Range
Set rng = src.Worksheets("l04").Range(src.Worksheets("l04").Range("Z7:AK7"), src.Worksheets("l04").Range("Z7:AK7").End(xlDown)).SpecialCells(xlCellTypeVisible)
My expected result from this Line of Code should be, that the Range rng is set from Z7 to AK7 all the way down to the maximum number of rows, but only those which are visible.
Edit1: Changed SpecialCell --> SpecialCells
Dim cell As Range
Dim lastRow As Long
With src.Worksheets("104")
lastRow = .Cells(.Rows.Count, "Z").End(xlUp).row
With .Range("Z7:AK" & lastRow)
For Each cell In .Columns(1).SpecialCells(xlCellTypeVisible)
Debug.Print Intersect(.Cells, cell.EntireRow).Address ' change this to what you actually need to grab from each visible cell
Next
End With
End With
Based on some clues in your question, you may find that using the Intersect Method is advantageous.
Dim rng as Range
With src.Worksheets("l04")
'gets all visible cells within the used range on your sheet
set rng = .UsedRange.SpecialCells(xlCellTypeVisible)
'Use the Intersect method to select specific columns
set rng = Intersect(rng, .range("AB:AB, AD:AD"))
End With
Note: This will not select down to last row (i.e. row 1,048,576), only to the last row with data in the specified range.
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
How can i modify the code below to select data from any worksheets and copy they to another worksheet for example select and copy data from Worksheets("uno") and paste they to Worksheets("duo"). Because the code below selects data only on activesheet
Set tbl = ActiveCell.CurrentRegion
tbl.Resize(tbl.Rows.Count, tbl.Columns.Count).Select
I have a code to copy data from any sheet to another for example
Worksheets("uno").Range("A5:T5,A7:T56,W5,Y5,W7:W56,Y7:Y56").Copy _
Worksheets("duo").Range("B4")
But i want to copy a range with data and ignore blank cells because the range A5:T5 it doesn't have always all cells with data concretely the last cells of this range, two or three of those, and also the same on range A7:T56.
My problem is how to select a range with data and ignore the blank cells inside the range A7:T56 concretely the last rows and the last columns which haves blank cells
Well, for the first part, where "the code selects data only on the activesheet", you just need to activate the correct sheet (for example: "Worksheets("uno").Activate") before executing "Set tbl = ActiveCell.CurrentRegion".
I am not really sure if I understand you correctly, but these are my thoughts:
If you don't want to activate worksheet "uno" you need to create a reference to that worksheet to have a direct access to it:
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Set wkb = Excel.Application.Workbooks("<name of your workbook>")
Set wks = wkb.Worksheets("uno")
If you now use the following code:
wks.Range("<your range>").Copy
you have just copied your selected cells, now you can paste it wherever you want.
As for the part with avoiding empty cells:
Generally speaking, you need to create a method of checking whether relevant cells are empty or not before you add them to your range.
Personally, I would avoid trying to copy the whole range as such. Instead I would:
1) loop through all relevant cells in your range one by one
2) for each cell check if it's empty
3) if empty, go to next cell
4) if not empty, copy that cell and paste to the target worksheet
5) jump to next relevant cell
6) when you reach the cell which is just after your last cell, quit looping
I would use the above defined wks object.
Note that a Range object can be treated as a collection of strings, so you can iterate using For... Next loop (For Each loop does not guarantee the index order).
Something like this should do:
Dim rng As Range
Set rng = wks.Range("<your range>")
Dim numOfItems As Integer, itm, i As Integer
numOfItems = rng.Count
For i = 1 To numOfItems
itm = rng.item(i)
If itm <> "" Then
'set value of the corresponding cell in your target worksheet to itm
'<relevant cell>.Value = itm
Else
'do nothing
End If
Next i
I hope it's at least a little bit helpful.
To start with I'm not really a wise man. So I was trying to add up two values and display them in a third (that's easy) but I also wanted it to repeat an infinite amount of times (namely that it does the same for every row, let's say I place the result in I5, I want also, on every I under it (I6, I7, I8, etc...)
Should it be:
Private Sub Worksheet_Change()
if IsNumeric(Range("B1").sort) And IsNumeric(Range("B2").sort) then
Dim value1 As Single
Dim value2 As Single
range(I5).sort = value+1 + value2
End Sub
Or as I think I'm horribly mistaken?
You're using the .Sort property of Range where you should be using .Value.
There's a couple of ways to achieve what you're looking to do. First option is to iterate through the range and add the relevant value to each cell like so:
Public Sub addCells()
Dim rng As Range, cell As Range
'Set the sheet name
With ThisWorkbook.Worksheets("Sheet_Name")
'Set the range below:
Set rng = .Range("I1:I10")
'Loop through range and add cells together
For Each cell In rng
cell.Value = cell.Offset(0, 2) + cell.Offset(0, 1)
Next cell
End Sub
Another way to do it if the values to be added is ordered in for example column A and B would be:
Public Sub addCells()
Dim rng As Range, cell As Range
'Set the sheet name
With ThisWorkbook.Worksheets("Sheet1")
'Add the first formula to the sheet
.Range("C1").Value = "=SUM(A1+B1)"
'Change the range below to the range to be filled
.Range("C1").AutoFill Destination:=.Range("C1:C10")
End With
End Sub
I am using an Index/Match to get data from a related table to populate in the first table. In my related table I have filtered out values, but the filtered out values are still populating in my first table. If Index/Match is not smart enough to only grab the filtered values, how can I work around this (formula preferred, but VBA acceptable) to get only the filtered values.
Here is my current formula:
=INDEX(Table_owssvr__1[MyValues],MATCH([#[ID]],Table_owssvr__1[ID],0))
You might find the SUBTOTAL function useful, as it only works on visible rows. (Here's some more general discussion about SUBTOTAL)
But if that's not flexible enough for your needs, here's how to check whether a certain cell is filtered out or not.
Using this, I've written a bit of VBA code to sum over a column summing only visible cells. Should be a pretty useful start in doing whatever you need to do.
If summing over the cells is not what you want to do, just change the part indicated in the comments. (Obviously you'd have to change the name of the function from sumFilteredColumn to something else!)
Public Function sumFilteredColumn(startCell As Range)
Dim lastRow As Long ' the last row of the worksheet which startCell is on
Dim currentCell As Range
Dim runningTotal As Long ' keeps track of the sum so far
lastRow = lastRowOnSheet(startCell)
Set currentCell = startCell
' Loop until the last row of the worksheet
Do While currentCell.Row <= lastRow
' Check currentCell is not hidden
If Not cellIsOnHiddenRow(currentCell) Then
' -------------------------------------------------
' Here's where the magic happens. Change this to
' change sum to, e.g. concatenate or multiply etc.
If IsNumeric(currentCell.Value) Then
runningTotal = runningTotal + currentCell.Value
End If
' -------------------------------------------------
End If
Set currentCell = currentCell.Offset(1) ' Move current cell down
Loop
sumFilteredColumn = runningTotal
End Function
' return the number of the last row in the UsedRange
' of the sheet referenceRange appears in
Public Function lastRowOnSheet(referenceRange As Range) As Long
Dim referenceSheet As Worksheet
Dim referenceUsedRange As Range
Dim usedRangeCellCount As Long
Dim lastCell As Range
Set referenceSheet = referenceRange.Parent
Set referenceUsedRange = referenceSheet.usedRange
usedRangeCellCount = referenceUsedRange.Cells.CountLarge
Set lastCell = referenceUsedRange(usedRangeCellCount)
lastRowOnSheet = lastCell.Row
End Function
' Is the row which referenceCell is on hidden by a filter?
Public Function cellIsOnHiddenRow(referenceCell As Range) As Boolean
Dim referenceSheet As Worksheet
Dim rowNumber As Long
Set referenceSheet = referenceCell.Parent
rowNumber = referenceCell.Row
cellIsOnHiddenRow = referenceSheet.Rows(rowNumber).EntireRow.Hidden
End Function
LondonRob mentioned the SUBTOTAL function. AGGREGATE is a more general function than SUBTOTAL that operates with knowledge of both hidden and filtered cells (there is a difference). They'll do that without addins or VBA, though with somewhat hard-to-read formulae.
I learnt it from here.
I have been able to get this working by the following:
1) Create three worksheets, one for clients, one for purchases, and one for purchasesforclient.
2) Create a Macro to copy filtered values to a new worksheet:
Sub Purchases()
Dim Rng As Range
Set Rng = Worksheets("Comments").Columns("A")
Set Rng = Rng.Resize(65535, 1).Offset(1, 0)
Set Rng = Rng.Resize(, 5).SpecialCells(xlCellTypeVisible)
Rng.Copy Worksheets("PurchasesforClient").Range("A2")
End Sub
3) When I update the purchases via a filter, I run the macro in step 2 by creating a subtotal field and triggering the macro as follows. Since it is a formula, it requires a calculation to occur. This is embedded in the purchases sheet as VBA where the filtering is occurring, where B23 is the subtotal field that changes when it counts the amount of items once a filter is applied:
Public CurrentValue As Double
Private Sub Worksheet_Activate()
CurrentValue = Application.WorksheetFunction.Sum(ActiveSheet.Range("B23"))
End Sub
Private Sub Worksheet_Calculate()
If Application.WorksheetFunction.Sum(Range("B23")) <> CurrentValue Then Purchases
End Sub
4) I use the now filtered values in the purchasesforclient worksheet for my index/match formula in the clients worksheet. This allows me to dynamically filter by date, purchase type, etc. and have updated information in the clients worksheet
This answer requires MOREFUNC addon*
=INDEX(ARRAY.FILTER(Table_owssvr__1[MyValues]),MATCH([#[ID]],ARRAY.FILTER(Table_owssvr__1[ID]),0))
ARRAY.FILTER() function "Stores only the visible cells of a range (for instance a filtered range) in an array and returns this array. "
*MOREFUNC ADDON
Morefunc Addon is a free library of 66 new worksheet functions.
HERE is some information (by original author)
here is the last working download link I found
here is a good installation walk-through video