Counting Blank and Non-Blank cells - vba

I would like to count all the blank and non-blank cells in a given range of data only until the cell with a data. But I also have a limited to refer on only, its from O4:O18.
Given from the sample above, I only have to count blank cells from Row4 to the cell with data which is asd. Any help? Thanks!
The use of count is to count the blank cells within the non-blank cells. lets say that the last row with data is 15, so 15 will be the last row with data and from row 4 to row 15, will count the blank cells in the Range.

you can easely achieve desired result using worksheetfunction, try this:
Sub test()
Dim iBlank&, iNonBlank&, rng As Range
Set rng = Range("O4:O" & [O4:O18].Find("*", , , , , xlPrevious).Row)
With WorksheetFunction
iNonBlank = .CountA(rng)
iBlank = .CountBlank(rng)
End With
MsgBox "Blank: " & iBlank & vbNewLine & "NonBlank: " & iNonBlank
End Sub

I am not 100% sure about what is your goal. I understand that you have a maximum range from "O4" to "O18" (it can be smaller) and you want to go from "O4" to the last non blank cell in that range, count the number of blank and non-blank cells. If it is indeed what you want to do, try the code below (explanations are in it):
Sub CountingBlankAndNonBlank()
Dim MyRange As Range
Dim LastRow As Long, TotalRange As Long
Dim CountBlank As Long, CountNonBlank As Long
'Find the last row with data in the Range("O4:O18")
LastRow = 19 - Range(Cells(18, 15), Cells(Rows.Count, 15).End(xlUp)).Count
'Set a range from "O4" to last cell with data
Set MyRange = Range(Cells(4, 15), Cells(LastRow, 15))
'How many cells in my Range
TotalRange = LastRow - 3
'How many blank cells in my Range
CountBlank = MyRange.SpecialCells(xlCellTypeBlanks).Count
'How many non-blank cells in may range (Total - Blank)
CountNonBlank = TotalRange - CountBlank
MsgBox "There are:" & vbNewLine _
& " - " & CountBlank & " blank cells" & vbNewLine _
& " - " & CountNonBlank & " non-blank cells" & vbNewLine _
& " - " & LastRow & " would be the lastrow"
End Sub

Count blank cells (returns 3 in your 2nd example and #N/A if all cells blank):
=COUNTBLANK($O$4:INDEX($O$4:$O$18,LOOKUP(2,1/($O$4:$O$18<>""),ROW($O$4:$O$18))-3))
Count non-blank cells (returns 6 in your 2nd example and 1 if all cells blank):
=COUNTA($O$4:INDEX($O$4:$O$18,LOOKUP(2,1/($O$4:$O$18<>""),ROW($O$4:$O$18))-3))
Using the Lookup formula from here: What is this programmer doing with his Lookup function?

Related

Check cell values in two different sheets

I have two sheets in an excel file namely bank_form and Pay_slip.
I am trying to write a vba to check whether value/text in cell B5 of sheet Pay_slip is equal to value/text in cell B8 of sheet Bank_form. Similary it will check all values till the last row of sheet Pay_slip.
But my code is not working it always comes true i.e. it always flash the message "All employees found."
Please find my mistake(s).
Sub CommandButton1_Click()
Dim LastRow As Long
LastRow = Worksheets("Bank_form").Range("B" & Rows.Count).End(xlUp).Row
LR = Worksheets("Pay_slip").Range("B" & Rows.Count).End(xlUp).Row
If Worksheets("Pay_slip").Range("B5" & LR).Value = Worksheets("Bank_form").Range("B8" & LastRow) Then
MsgBox "All Employees Found."
Worksheets("Bank_form").Range("F" & LastRow + 1).Formula = "=SUM(F8:F" & LastRow & ")"
Else: MsgBox "Employee(s) missing Please check again!"
End If
End Sub
you will need a loop something like this
Dim i as Long
For i = 5 to LastRow 'start at B5
If Worksheets("Pay_slip").Range("B" & i).Value = Worksheets("Bank_form").Range("B" & i + 3) Then
' ... your other stuff here
next i
If Worksheets("Pay_slip").Range("B5").Value = Worksheets("Bank_form").Range("B8").Value Then MsgBox "The values are the same"
I have no idea why you involved the number of rows in your code but they are useless in order to check the equivalence in the values in a specific cell only

VBA Macro - I want to change each cell value to a new one in a specific range... how to do it? Excel

I have a range that is B3:B500
I want to change the value in each cell in that range
The range however, is dynamic so I need to look from B3 to last row
First:
How do I get it to change the range to work to last row rather than preset range?
Second:
I want to change each individual cell value to something like this:
myCell.Value = "=" & Chr(34) & Chr(61) & myCell.Value & Chr(34)
How do I get it to go through cell by cell to make change to each cell in the "dynamic" range we just created?
Appreciate all the help I can get... pretty new at VBA so please bear that in mind and keep it simple :)
I.e. Cell b3 contains: "ASP" (Text only)
Change to: ="="ASP" (formula instead giving result =ASP)
Dim lastRow As Integer: lastRow = 3
Dim myCell As Range
'determine last row of current region
Do While(Not IsEmpty(Cells(lastRow + 1, 2)))
lastRow = lastRow + 1
Loop
'loop through the range
For Each myCell In Range(Cells(2, 2), Cells(lastRow, 2))
myCell.Value = "=" & Chr(34) & Chr(61) & myCell.Value & Chr(34)
Next myCell
In this code, first you determine last row using While loop, which loops until the last row in column is found. Then use For Each loop, where you loop through the range, from third row to last row in B column.

Vba to vlookup value & copy next cell value to invoice sheet

Formula use for Vlookup
activeWS.cell("A9") =INDEX(Breaking_Data!F5:F,MATCH(A8,Breaking_Data!A5:A,0))
I try to run it in VBA code but it doesn't work, any one know how to modify it for VBA code.
that lookup A8 cell value in ws("Breaking_Data") with Range("A5:A").lastcellvalue if any value match then copy same row cell value form range ("F5:F") & paste it in active sheet cell A9.
Try this:
dim lastR as Long: LastR = Worksheets("Breaking_Data").Range("A" & Rows.Count).End(xlUp).Row
activeWS.cell("A9").Value = Application.Evaluate _
("Index(Breaking_Data!F5:F" & lastR & ", Match(A8, Breaking_Data!A5:A" & lastR & ", 0))")
You have 2 options.
You can include it as a function:
activeWS.cell("A9") = "INDEX(Breaking_Data!F5:F1048576,MATCH(A8,Breaking_Data!A5:A1048576,0))"
or you can get the value itself:
activews.Range("A9") = Application.Index(Sheets("Breaking_Data").Range("F5:F1048576"), Application.Match(activews.Range("A8"), Sheets("Breaking_Data").Range("A5:A1048576"), 0))

Excel VBA range select

I have a macro in which I need to select the range R2:last row in sheet. However the last row in my sheet might be blank in column R. At the moment I am using this
Dim t As Range
Set t = Range("R2", Range("R1000").End(xlUp))
For Each Cell In t
If IsEmpty(Cell) Then
Cell.Activate
ActiveCell.Value = "To Be Picked Up"
End If
Next
However if the last row has a blank in column R then it gets ignored. I am hoping to pull the range using column A, as the last row of data always has column A. So something like,
Dim t As Range
Set t = Range("R2", Range("A1000").End(xlUp).ActiveCell.Offset(0, 17))
For Each Cell In t
If IsEmpty(Cell) Then
Cell.Activate
ActiveCell.Value = "To Be Picked Up"
End If
Next
It seems so simple but I'm sure im missing something stupid. Any help or alternative methods would be helpful thank you.
This should do the trick in one line:
Sub SO()
Range("R2:R" & Range("A" & Rows.Count).End(xlUp).Row).SpecialCells(xlCellTypeBlanks).Value = "To Be Picked Up"
End Sub
But in answer to your question specifically
Set t = Range("R2:R" & Range("A" & Rows.Count).End(xlUp).Row)
The Range() method will accept a string as an argument to obtain a range.So we can build this string any way we want:
"A1000" '// A1000
"A" & 1000 '// A1000
"A" & "10" & "00" '// A1000
"A" & CStr(1001 - 1) '// A1000
"A" & Rows.Count will return A65536 or A1048576 depending on the type of worksheet.
Range("A1048576").End(xlUp) as you know, will retrieve the last cell in that area, or the first cell in the next area on the direction specified.
Range("A1048576").End(xlUp).Row will return the row number of that cell (let's say it's A1000 for argument's sake) so the return value is 1000.
"R2:R" & Range("A" & Rows.Count).End(xlUp).Row therefore makes the string R2:R1000.
So finally, Range("R2:R" & Range("A" & Rows.Count).End(xlUp).Row) is the same as Range("R2:R1000")

Creating excel macro to take info from form and append it onto bottom of list

I am currently working on a spreadsheet to help track individuals who attend a weekly meeting conducted by my department. I am trying to automate the process of tracking by using a macro to copy values from a list/form that a member of my department will enter the attendees email and the date. The email and date will then be added together (=a&b) to generate a value and that value will be used to mark whether the individual is present or not at that particular meeting. View Image of form/table
A report is generated after the meeting to tell which individuals have attended and how long they were on the call for. Before I was taking this report and pasting it onto the bottom of the original list but this has become inefficient as the columns and table length have changed. What I would like to do is take the emails, dates, and value on spreadsheet from the calculate tab and have those values append onto the bottom of the list on the reports tab without altering any of the previous information. View Image of reports tab
After the values have been appended to the bottom of the report, I have another tab called meeting dates. This contains a formula that will determine whether the individual was present or not by marking it with either ā€œYā€ or ā€œNā€. Forgot to mention that every week it is the same 17 individuals that are attending these meetings. Eventually I would like to have it so that if the date entered on the calculate tab is not present on the meeting dates tab, add the date to the meeting dates tab.
I am still very new to Excel VB and macros however do have some programming experience. Just not in excel. If somebody could help me, that would be awesome!
This answer is an attempt to get your started.
If you search the internet for "Excel VBA Tutorial" you will get many hits. Try a few because they are all different and pick the one you like best. Work through that tutorial to get a general feel for Excel. I do not believe you will be successful finding bits of relevant code without that general feel.
Do not try to describe your entire problem because I doubt anyone will respond. Instead try to break your problem down into little steps and seek help with those steps.
For example, you will need to determine the number of rows in the post-meeting report so you can access that data. You then want to add that data to the bottom of the previous list. In both cases you need to determine the last used row in a worksheet. "Excel VBA: How to find last row of worksheet?" is a simple question and you will be able to find multiple answers. I give my response to that question below.
I assume the post-meeting report and the list you are creating are in different workbooks. Your macro could be in the same workbook as the list or it could be in a different workbook. Macros can access their own workbooks, any other workbook that happens to be open or they can open as many other workbooks as required. Again "Excel VBA: How do I work with several workbooks?" should result in plenty of hits.
I have not tried either of my questions. I find "Excel VBA:" helps but you may require several attempts before you find the just the right question to get the answer you seek. But if your question is small and precise you should always be able to find an answer.
Let's return to the first question. An irritating feature of Excel VBA is that they are almost always several ways of achieving a similar effect. Create a new workbook, create a module and copy the code below to it. Run the macro FindFinal().
This macro demonstrates several methods of finding the last row and column. Every method has its problems and I have tried to show how how each method can fail. There is a lot of worksheet access within this macro which I believe will repay study. It should help you decide which method is appropriate for each of your requirements.
Option Explicit
Sub FindFinal()
Dim Col As Long
Dim Rng As Range
Dim Row As Long
' Try the various techniques on an empty worksheet
Debug.Print "***** Empty worksheet"
Debug.Print ""
With Worksheets("Sheet1")
.Cells.EntireRow.Delete
Set Rng = .UsedRange
If Rng Is Nothing Then
Debug.Print "Used range is Nothing"
Else
Debug.Print "Top row of used range is: " & Rng.Row
Debug.Print "Left column row of used range is: " & Rng.Column
Debug.Print "Number of rows in used range is: " & Rng.Rows.Count
Debug.Print "Number of columns in used range is: " & Rng.Columns.Count
Debug.Print "!!! Notice that the worksheet is empty but the user range is not."
End If
Debug.Print ""
Set Rng = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious)
If Rng Is Nothing Then
Debug.Print "According to Find the worksheet is empty"
Else
Debug.Print "According to Find the last row containing a value is: " & Rng.Row
End If
Debug.Print ""
Set Rng = .Cells.SpecialCells(xlCellTypeLastCell)
If Rng Is Nothing Then
Debug.Print "According to SpecialCells the worksheet is empty"
Else
Debug.Print "According to SpecialCells the last row is: " & Rng.Row
Debug.Print "According to SpecialCells the last column is: " & Rng.Column
End If
Debug.Print ""
Row = .Cells(1, 1).End(xlDown).Row
Debug.Print "Down from A1 goes to: A" & Row
Row = .Cells(Rows.Count, 1).End(xlUp).Row
Debug.Print "up from A" & Rows.Count & " goes to: A" & Row
Col = .Cells(1, 1).End(xlToRight).Column
Debug.Print "Right from A1 goes to: " & ColNumToCode(Col) & "1"
Col = .Cells(1, Columns.Count).End(xlToLeft).Column
Debug.Print "Left from " & Columns.Count & _
"1 goes to: " & ColNumToCode(Col) & "1"
' Add some values and formatting to worksheet
.Range("A1").Value = "A1"
.Range("A2").Value = "A2"
For Row = 5 To 7
.Cells(Row, "A").Value = "A" & Row
Next
For Row = 12 To 15
.Cells(Row, 1).Value = "A" & Row
Next
.Range("B1").Value = "B1"
.Range("C2").Value = "C2"
.Range("B16").Value = "B6"
.Range("C17").Value = "C17"
.Columns("F").ColumnWidth = 5
.Cells(18, 4).Interior.Color = RGB(128, 128, 255)
.Rows(19).RowHeight = 5
Debug.Print ""
Debug.Print "***** Non-empty worksheet"
Debug.Print ""
Set Rng = .UsedRange
If Rng Is Nothing Then
Debug.Print "Used range is Nothing"
Else
Debug.Print "Top row of used range is: " & Rng.Row
Debug.Print "Left column row of used range is: " & Rng.Column
Debug.Print "Number of rows in used range is: " & Rng.Rows.Count
Debug.Print "Number of columns in used range is: " & Rng.Columns.Count
Debug.Print "!!! Notice that row 19 which is empty but has had its height changed is ""used""."
Debug.Print "!!! Notice that column 5 which is empty but has had its width changed is not ""used""."
Debug.Print "!!! Notice that column 4 which is empty but contains a coloured cell is ""used""."
End If
Debug.Print ""
Set Rng = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious)
If Rng Is Nothing Then
Debug.Print "According to Find the worksheet is empty"
Else
Debug.Print "According to Find the last row containing a formula is: " & Rng.Row
End If
' *** Note: search by columns not search by rows ***
Set Rng = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByColumns, xlPrevious)
If Rng Is Nothing Then
Debug.Print "According to Find the worksheet is empty"
Else
Debug.Print "According to Find the last column containing a formula is: " & Rng.Column
End If
' *** Note: Find returns a single cell and the nature of the search
' affects what it find. Compare SpecialCells below.
Debug.Print ""
Set Rng = .Cells.SpecialCells(xlCellTypeLastCell)
If Rng Is Nothing Then
Debug.Print "According to SpecialCells the worksheet is empty"
Else
Debug.Print "According to SpecialCells the last row is: " & Rng.Row
Debug.Print "According to SpecialCells the last column is: " & Rng.Column
End If
Debug.Print ""
Row = 1
Do While True
Debug.Print "Down from A" & Row & " goes to: ";
Row = .Cells(Row, 1).End(xlDown).Row
Debug.Print "A" & Row
If Row = Rows.Count Then Exit Do
Loop
End With
With Worksheets("Sheet2")
.Cells.EntireRow.Delete
.Range("B2").Value = "B2"
.Range("C3").Value = "C3"
.Range("B7").Value = "B7"
.Range("B7:B8").Merge
.Range("F3").Value = "F3"
.Range("F3:G3").Merge
Debug.Print ""
Debug.Print "***** Try with merged cells"
Set Rng = .UsedRange
If Rng Is Nothing Then
Debug.Print "Used range is Nothing"
Else
Debug.Print "Used range is: " & Replace(Rng.Address, "$", "")
End If
Debug.Print ""
Set Rng = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious)
If Rng Is Nothing Then
Debug.Print "According to Find the worksheet is empty"
Else
Debug.Print "According to Find the last cell by row is: " & Replace(Rng.Address, "$", "")
End If
Set Rng = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByColumns, xlPrevious)
If Rng Is Nothing Then
Debug.Print "According to Find the worksheet is empty"
Else
Debug.Print "According to Find the last cell by column is: " & Replace(Rng.Address, "$", "")
End If
Debug.Print "!!! Notice that Find can ""see"" B7 but not F3."
Debug.Print ""
Set Rng = .Cells.SpecialCells(xlCellTypeLastCell)
If Rng Is Nothing Then
Debug.Print "According to SpecialCells the worksheet is empty"
Else
Debug.Print "According to SpecialCells the last row is: " & Rng.Row
Debug.Print "According to SpecialCells the last column is: " & Rng.Column
End If
End With
End Sub
Function ColNumToCode(ByVal ColNum As Long) As String
Dim Code As String
Dim PartNum As Long
' Last updated 3 Feb 12. Adapted to handle three character codes.
If ColNum = 0 Then
ColNumToCode = "0"
Else
Code = ""
Do While ColNum > 0
PartNum = (ColNum - 1) Mod 26
Code = Chr(65 + PartNum) & Code
ColNum = (ColNum - PartNum - 1) \ 26
Loop
End If
End Function
In the code above, I access worksheet cells directly with statements such as .Range("B2").Value = "B2". This can be slow particularly when you are moving data from one worksheet to another. An alternative approach is to use arrays.
Dim Rng As Range
Dim ShtValues as Variant
With Worksheets("Xxxx")
Set Rng = .Range(.Cells(Row1, Col1), .Cells(Row2, Col2))
End With
ShtValues = Rng.Value
A Variant is a variable that can hold anything including an array. ShtValues = Rng.Value converts ShtValues to a two-dimensional array hold all the values within Rng. Processing values within an array is much faster that accessing them in the worksheet.
.Range(.Cells(Row1, Col1), .Cells(Row2, Col2)) is perhaps the easiest way of creating a range specifying the worksheet area with Cells(Row1, Col1) as the top left cell and Cells(Row2, Col2) as the bottom right.
If I understand correctly, you want to move data from the post-meeting report to the list but the sequence of columns in the report and list are not the same. This suggests you need to move the data as columns. Using .Range(.Cells(Row1, Col1), .Cells(Row2, Col2)) and with Col1 = Col2, you can define a range that is a column.
Rng1.Copy Destination := Cell2
The above statement will copy the contents of Rng1 to the range starting at Cell2. A statement like this for each column of data in the report may be the easiest way of copying the data.
I hope the above gives you a start.