Excel VBA - Fill in empty database cells with variable range formula - excel

I have a database containing "N/A" at different cells, caused by temporary system offline.
I used to fill these "N/A"'s using the formula shown with the image:
As you can see, the datum at columns A are cumulative, so are B and C. The "N/A"s are compensated by spreading the difference between the last reading before the first "N/A" and the first reading after the last "N/A"
The "N/A"'s appear at different points and have varying lengths.
Is there maybe a vba code to help me do this in one click for the entire database?
Thank you sirs for your kind help.

You could try running this VBA code to interpolate the N/A values based on numbers above and below:
Sub FillNA()
Dim rng As Range, col As Range, a As Range
Set rng = Cells.SpecialCells(xlCellTypeConstants, xlTextValues)
For Each col In ActiveSheet.UsedRange.Columns
If Not Intersect(rng, col) Is Nothing Then
For Each a In Intersect(rng, col).Areas
If a(1) = "N/A" Then
a(0).Resize(a.Count + 2).DataSeries Trend:=True
End If
Next a
End If
Next col
End Sub
(If N/A appears at the beginning or end of the range you will need to decide how to handle this case and make appropriate adjustments)

Related

VBA for filtering cells in a row based on another cell value in the same row

I have an excel sheet with numbers in each cell. I want to eliminate the cells containing values which are larger than a specific value, different for each row, for example in the picture
I want to eliminate all the cells in a certain row that has values more than the BL cell.
Not sure the exact context in which this is being used, So possibly some conditional formatting would be more stable?
Also not sure what you meant by "Eliminate" so the following code just turns the cell red.
anyway, hopefully this code will help you get started :)
Sub Cell_Vaue_Check()
Dim row As Excel.Range
Dim cel As Excel.Range
For Each row In Sheets("Sheet1").Range("A1:C5").Rows '<<- Replace "Sheets("Sheet1").Range("A1:C5")" with the Sheet and Range you want to check
For Each cel In row.Cells
If cel.Value > Range("E" & cel.row).Value Then '<<- Replace "E" with the Column in which the check value is located
cel.Interior.Color = RGB(288, 0, 0) '<<- This line turns the cell Red. Replace it with whatever code you want depending on what "eliminate" means to you
End If
Next
Next
Set row = Nothing
Set cel = Nothing
End Sub
If Anybody has any improvements please feel free to Add!

Looking to loop through a column in excel and highlight fill each cell if the content matches that of another column

My issue now is with my conditional formatting rules - they are working as expected up to a certain point in column W, which is where the cells should be either highlighted or passed over. I have included a set of data from column W and column Z (the reference data) where there are matches that are not being highlighted. In the Column W data I have bolded the numbers that should be highlighted.
Column Z - Z506-Z550
233892
233899
959460
156311
515114
549794
562793
372953
230659
230717
2051205586
364834
790760
334588
538149
288261
19326
267428
Net 90
473853
3211221994
264556
260798
156271
509597
2211211506
800990
597593
431759
377289
224118
178966
276840
430269
431923
431986
547439
512399
234975
512203
602547
443537
376759
284287
608745
Column W - W1144-W1155
233892
367164
368384
344813
233899
233899
233895
-
233917
284287
376759
443537
The conditional formatting formula I have is =VLOOKUP($W4,$Z4:$Z922,1,FALSE) 'Applies To' =$W$4:$W$3600
I am not sure what is causing this conditional formatting to fail here.
Ignore below - now working with conditional formatting instead of vba
I am trying to automate a manual process of cross referencing data and highlighting a cell if the contents are found anywhere in another column of data. However, the amount of data in both of these columns is not the same. And unfortunately, the column I need to loop through and check each cell often has either blank cells or cells that are dashed ("---").
I started with conditional formatting but it was not working properly so I am now on VBA.
Private Sub Workbook_Open()
Dim LastRow As Long
Range("W4").Select
LastRow = Range("W4").End(xlDown).Row
Do Until ActiveCell.Row = LastRow
If Not IsEmpty(Application.Match(ActiveCell.Value, Range("Z:Z"), 0))
Then
ActiveCell.Interior.Color = vbGreen
ActiveCell.Offset(1, 0).Select
End If
Loop
End Sub
Right now the code has a couple issues. It is not finding the last row correctly - when debugging it shows as 65, but should be 3,535 in the test case I'm using. Additionally, my match statement is not working, as it is highlighting every cell instead of only those whose content is found in column Z. And, it highlights up to row 410, which means my Do Until loop must be wrong as well.
After figuring out the one column I eventually need to allow checking columns AA and AB for content matches.
Thanks!
As mentioned in the comment, conditional formatting is the way to go. I just tried the following as a conditional format.
=VLOOKUP($A2,$C$2:$C$7,1,FALSE)
A column of numbers in A as the numbers to be cross-referenced, and a list in column C which are the numbers to be checked. It works perfectly.
I recommend to use Conditional Formatting. The following is just to explain what was wrong with your code:
Always define which worksheet you mean and avoid using Select in Excel VBA.
Using End(xlDown) will find the next free cell (not the last used). Instead use End(xlUp) from the very last cell of the worksheet.
Application.Match does not return a cell but a row number. Therefore IsEmpty does not work.
In the end something like this should work:
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("SheetName")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "W").End(xlUp).Row
Dim MatchRow As Variant
Dim iRow As Long
For iRow = 4 To LastRow
MatchRow = 0 'initialize
MatchRow = Application.Match(ws.Cells(iRow, "W").Value, ws.Range("Z:Z"), 0)
If MatchRow > 0 Then
ws.Cells(iRow, "W").Interior.Color = vbGreen
End If
Next iRow
Note that Contidional Formatting would be a much better solution.

How to loop through "blocks" of rows in excel dataset instead of each row individually (VBA)?

I'm trying to loop through a data set in Excel where the deciding factors for each block of rows is based on the second column (WO#) because I want to perform calculations (not part of this question) just for items in the same grouping.
Visualization on iterating through blocks of rows
Sub test()
Dim totalHrs As Integer, lastRow As Integer
Dim block As Range, dataSet As Range
lastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Set dataSet = Range("A2:G" & lastRow)
For Each block In Columns("B").SpecialCells(xlCellTypeConstants, xlTextValues).Areas
'Do calculation stuff
Next block
End Sub
Right now I am having trouble defining what range 'block' should be since it will constantly change. A block begins when the "WO#" column is one number, and the block ends once that column's value changes to something else. How do I go about defining this range?
An easier way would be to just extract rows that have the same WO# into a new table and do the calculations there, but since this dataset can get quite large I would prefer not to do that as the macro will become way too heavy
What if you added this into G11 =IF(B11=B12,F12,C11) and then in F11 you added =G11-E11 and then dragged them down.
It should check to see if it's the last entry in the set and then set itself to the delivery date or set itself equal to the start day of the line below.
Edit:
Try replacing the F11 cell with this =WORKDAY(G11,-E11) and dragging down to account for workdays. To account for holidays, you can create a second sheet to list them out as dates and then add them as a range for the third, optional, argument in the Workday function. Please see the Workday documentation if more clarification is required on the function's use.
The code below defines blocks of similar values in a column. To use this code, either add a column to your worksheet combining columns B and C into one value (=B11&C11) or edit the code to check two columns (If rngCell.Offset(0, 0).Value = rngCell.Offset(1, 0).Value And rngCell.Offset(0, 1).Value = rngCell.Offset(1, 1).Value Then). Also, expand the blocks to more than one column.
'Starts the first block with the first cell in a column.
Set rngBlock = rngColumn.Cells(1)
'Checks every cell in a column.
For Each rngCell In rngColumn
'Checks whether a cell's value equals the cell below it.
If rngCell.Value = rngCell.Offset(1, 0).Value Then
Set rngBlock = Union(rngBlock, rngCell.Offset(1, 0))
'If equal, includes the cell below in the block.
Else
'If not equal, does something with the block...
Debug.Print rngBlock.Address
'Starts the next block with the cell below.
Set rngBlock = rngCell.Offset(1, 0)
End If
Next rngCell

Selecting an area with exception of merged cells in dynamic range

IMPORTANT EDIT: The main issue here is caused by hidden merged cells that are causing the entirity of their active range to be selected. Unless you know a way how to dynamically skip merged cells (in a dynamic range), the it most likely won't help. Have changed the entirity of question accordingly
any idea what am I doing wrong?
Got the following code, fyi the function find_last_row returns the value of last active row as integer. In this case, the returned variable would be 40
Private Sub initalize_button_Click()
Dim lastRow As Integer
Dim ws As Worksheet: Set ws = Sheets("Training_Planner")
lastRow = find_last_row
With ws
.Activate
.Range("E5:H" & lastRow).Select
End With
End Sub
Pretty basic code, should open the worksheet Training_Planner and select from E5 to HlastRow (in this case lastRow is 40) so the selected range should be E5:H40
Here is the expected result:
What I get instead:
Curiously enough, it selects only active range, but it's as if it didn't pay attention to columns, instead of the expected E5:H40 i get B5:I40
Any idea what's causing this?
Ok, first of all, if your range is gonna start always as E5, your range is 50% dinamic, because it starts always in same column and same row. Your Range is (Cells(a,b),Cells(c,d)), this means a = 5 and b = 5 (Column E).
Also, you say and Inputbox asks users for end cell of range (in your example is H40, but this is dynamic).
So, my code checks EVERY SINGLE cell in the range formed, and then, using Application.UnionI set a final big range. We cannot just use an array to select all of them, because your range is dynamic, and selecting ranges with arrays is limited to 30 args, so we need to update our FinalRange for each cell.
Dim MyCell As Range
Dim RangeWanted As Range
Dim MyFinalRange As Range
Set RangeWanted = Range("E5:" & InputBox("Cell Address")) 'User inputs Final Cell of Range. Start is always E5
'let's get all invididual addresses of each cell inthat dynamic RangeWanted
For Each MyCell In RangeWanted
If MyCell.MergeCells = False Then 'If not merged, we add it to FinalRange
If MyFinalRange Is Nothing Then
Set MyFinalRange = MyCell
Else
Set MyFinalRange = Application.Union(MyFinalRange, MyCell)
End If
End If
Next MyCell
Set RangeWanted = Nothing
MyFinalRange.Select
With this code, from Range("E5:H40") in image,yellow cells are merged. I want to select only the not merged ones. And using this code, I get this:
My example is with Range("E5:H40") but it works also with other ranges.
Try it and adapt the code to your needs.
Whenever something small like this is happening, simply try to simplify as much as you can. In your case, it would be this:
Sub TestMe()
Worksheets("Training_Planner").Range("E5:H40").Select
End Sub
If it selects E5:H40 then everything is ok. If not, try to select it manually. Probably you have a hidden row, which is merged from B to I, thus it is happenning this way.
Instead of this:
.Range("E5:H" & lastRow).Select
Try going with this:
.Range("E5", (Cells(Rows.Count, "H").End(xlUp))).Select
It count all the rows "H" has and then goes up until it finds the first item. And it will then select from "E1" to last item in "H"

How do I get the current cell number whilst looping through a range of cells (Excel VBA)

I'm trying to get the current cell number whilst looping through a range of cells.
For Each i In Sheet3.Range("A3:A213")
msgbox(Sheet3.Range("B"&currentcellnumberinloop).Value)
Next
The purpose of this is to retrieve a value from another cell in the same row e.g. A1 and B1.
The i is probably declared as Range object(or Variant). Therefore to get the row number and retrieve the value in neighboring B column you have to call the .Row method of the i object
Sub ForEachAndFor()
Dim i As Range
For Each i In Sheet3.Range("A3:A213")
MsgBox Sheet3.Range("B" & i.Row).Value
Next
End Sub
You could also use the Offset(how_many_rows_up_or_down, how_many_columns_left_or_right)
you indicate rows down with a positive number an rows up with a negative number
same applies to the columns, use - to navigate to the left of the current cell, and positive number to the right of the current cell.
Sub ForEachSub()
Dim i as Range
For Each i in Sheet3.Range("A3:A213")
MsgBox i.Offset(0, 1).Value
next i
End Sub
Try this
Dim i as Integer
For Each i In Sheet3.Range("A3:D213").Rows.Count
msgbox(Sheet3.Range("B" & i).Value)
Next i
In your code variable i is of a Range type, thus you have to treat it that way. You can use Offset to get to what is in relation to your i address, like that:
For Each i In Sheet3.Range("A3:A213")
MsgBox (i.Offset(0, 1).Value)
Next i

Resources