Fill blank cells based on non blank cell above - excel

I want to fill blank cells in sequential order based on the cell above.
The interval to be filled for column F is not consistent. Need to fill down two up to 20 rows based on the item number above.
Need VBA and not a formula.
This code would copy the item above the non blank and paste it down.
Sub FillBlanks()
Columns("F:F").Select
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.FormulaR1C1 = "=R[-1]C"
End Sub
What I need is to autofill in sequence until the next nonblank.
Something like:
OA205S061169
OA205S061170
OA205S061171
OA205S061172
OA205S061173
OA205S061174

You can select your blank cells, as you are already doing, and then loop through each area, as follows...
Sub FillBlanks()
Dim lastRow As Long
Dim dataRange As Range
Dim currentArea As Range
lastRow = Cells(Rows.Count, "F").End(xlUp).Row
On Error Resume Next
Set dataRange = Range("F1:F" & lastRow).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not dataRange Is Nothing Then
For Each currentArea In dataRange.Areas
With currentArea
With .Offset(-1, 0).Resize(.Rows.Count + 1)
.Cells(1).AutoFill Destination:=.Cells, Type:=xlFillDefault
End With
End With
Next currentArea
End If
End Sub
Note that it uses Column F to find the last used row. However, depending on your data, you'll likely need to use some other column to determine the last used row. To use Column A, for example, use the following instead...
lastRow = Cells(Rows.Count, "A").End(xlUp).Row

Try
Sub FillTest()
Dim rngDB As Range
Dim vDB, vSplit
Dim i As Long, x As Long, n As Integer
Dim s As String
Set rngDB = Range("f1", Range("f" & Rows.Count).End(xlUp))
vDB = rngDB
For i = 1 To UBound(vDB, 1)
If vDB(i, 1) <> "" Then
vSplit = Split(vDB(i, 1), "S")
s = vSplit(0) & "S"
x = vSplit(1)
n = 0
Else
n = n + 1
vDB(i, 1) = s & Format(x + n, "000000")
End If
Next i
rngDB = vDB
End Sub

Related

Loop can't process array

I apologize for the vague title as I'm not really sure where the error is. I think I'm having some compability issues with copying the elements of an array and then manipulating that data.
This is the code I have so far:
Sub listNotCompletedTasks()
Dim cell As Range
Dim sourceRange As Range
Dim targetRange As Range
Dim notCompleted() As Variant
Dim i As Integer
Dim lastr As Integer
'define sourceRange
lastr = Range("A" & Rows.count).End(xlUp).Row
Set sourceRange = Range("A2:A" & lastr)
'notCompleted is an array with all the offset cells of the cells in sourceRange
'that don't contain a "Completed" string
i = 0
For Each cell In sourceRange.Cells
If cell.Offset(0, 2).Value <> "Completed" Then 'if the cell in column C does not contain "completed"...
ReDim Preserve notCompleted(0 To i)
notCompleted(i) = cell.Value 'add cell in column A to array
i = i + 1
End If
Next cell
'define targetRange
lastRow = Cells(Rows.count, "Z").End(xlUp).Row
Set targetRange = Range("Z1:Z" & lastRow)
'copy all elements from the array to the targetRange
For i = 0 To UBound(notCompleted)
targetRange.Offset(i, 0).Value = notCompleted(i)
Next i
End Sub
Expected output:
This works well. The problem begins with the second step:
Sub listNoDuplicatesAndNoOfInstances()
Dim sourceRangeZ As Range
Dim targetRangeB As Range
Set sourceRangeZ = Sheets("SourceData").Range("Z2")
Set targetRangeB = Sheets("TargetSheet").Range("B17")
'add all of the unique instances of a string in Z from the notCompleted() array
Do Until IsEmpty(sourceRangeZ)
If Application.WorksheetFunction.CountIf(Sheets("TargetSheet").Range("B:B"), sourceRangeZ.Value) = 0 Then
targetRangeB.Value = sourceRangeZ.Value
Set targetRangeB = targetRangeB.Offset(1, 0)
Else
End If
Set sourceRangeZ = sourceRangeZ.Offset(1, 0)
Loop
'count every instance of those strings and add the value to the respective cell to the right
Set targetRangeB = Sheets("TargetSheet").Range("C17")
Do Until IsEmpty(targetRangeB.Offset(0, -1))
targetRangeB.Formula = "=COUNTIF(SourceData!Z:Z,Z" & targetRangeB.Row & ")"
Set targetRangeB = targetRangeB.Offset(2, 0)
Loop
End Sub
The first loop (the one that adds every unique instance of the strings to column B) works. The second loop (the one that returns the number of instances of each string) does not work, only returning zeroes. The thing is, if I manually do the steps of the first subroutine (use a Pivot Table to filter out the rows I need, then copy the relevant row and paste it to column Z), and then call the second subroutine, then it actually works!
So I'm assuming the first subroutine is the culprit. A "cheap" workaround that worked for me was to copy the range in Z to another column (using sourceRange.Copy/targetRange.PasteSpecial xlPasteAll) and then call the second subroutine. What am I doing wrong, and is there a better way to solve this?
A 2D array you can copy to sheet without looping.
Sub listNotCompletedTasks()
Dim wsSource As Worksheet, arNotCompl()
Dim lastrow As Long, i As Long, n As Long
Set wsSource = ThisWorkbook.Sheets("SourceData")
With wsSource
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
ReDim arNotCompl(1 To lastrow, 1 To 1)
For i = 2 To lastrow
If .Cells(i, "C") <> "Completed" Then
n = n + 1
arNotCompl(n, 1) = .Cells(i, "A")
End If
Next
If n = 0 Then Exit Sub
'copy array to targetRange
lastrow = .Cells(.Rows.Count, "Z").End(xlUp).Row
.Cells(lastrow + 1, "Z").Resize(n) = arNotCompl
End With
End Sub
Add the formula in column C when you add the unique value to column B.
Sub listNoDuplicatesAndNoOfInstances()
Dim wsSource As Worksheet, wsTarget As Worksheet
Dim lastrow As Long, i As Long, n As Long
Dim arNotCompl(), v
Set wsSource = ThisWorkbook.Sheets("SourceData")
With wsSource
lastrow = .Cells(.Rows.Count, "Z").End(xlUp).Row
arNotCompl = .Range("Z2:Z" & lastrow).Value2
End With
Set wsTarget = ThisWorkbook.Sheets("TargetSheet")
n = 17
With wsTarget
For i = 1 To UBound(arNotCompl)
v = arNotCompl(i, 1)
If Application.WorksheetFunction.CountIf(.Range("B:B"), v) = 0 Then
.Cells(n, "B") = v
.Cells(n, "C").Formula = "=COUNTIF(SourceData!Z:Z,B" & n & ")"
n = n + 1
End If
Next
End With
End Sub

Loop, find cells with value then search column for the same cell and change its value

Detailed Problem
I'm attempting to write a VBA code that would loop through Column D,
if it finds Cells(i,"D") = "Good" then the code would search the entire column D for that value in cells (i,"D") and change all it's value to "Good"
Here is an Image on before the code.
Here is an Image after the code.
My Attempt:
Dim i As Integer
For i = 1 To Rows.Count
If Cells(i, "m") = "Good" Then
x = Cells(i, "m")
Next i
I think you would have to store the value ( ID Number ) and then search for it which I assigned "X". Once "X" is found change the status to "Good"
Use an AutoFilter
Option Explicit
Sub makeGood()
Dim i As Long, tmp As Variant
Dim dict As Object, k As Variant
'late bind a dictionary
Set dict = CreateObject("scripting.dictionary")
dict.CompareMode = vbTextCompare
With Worksheets("sheet11")
'remove any existing autofilters
If .AutoFilterMode Then .AutoFilterMode = False
'collect values from column D
tmp = .Range(.Cells(2, "D"), .Cells(.Rows.Count, "D").End(xlUp)).Value
'build dictionary of unique ID NUMs
For i = LBound(tmp, 1) To UBound(tmp, 1)
dict.Item(tmp(i, 1)) = vbNullString
Next i
'work with D:G range
With .Range(.Cells(1, "D"), .Cells(.Rows.Count, "G").End(xlUp))
'loop through unique ID NUMs
For Each k In dict.Keys
'autofilter on key
.AutoFilter field:=1, Criteria1:=k, visibledropdown:=False
'autofilter on Good
.AutoFilter field:=4, Criteria1:="good", visibledropdown:=False
'check for visible cells
If Application.Subtotal(103, .Offset(1, 0).Cells) > 0 Then
'remove the Good autofilter
.AutoFilter field:=4
'step down off the header and put Good in the filtered cells
With .Resize(.Rows.Count - 1, 1).Offset(1, 3)
.SpecialCells(xlCellTypeVisible) = "Good"
End With
End If
'clear autofilter
.AutoFilter field:=1
.AutoFilter field:=4
Next k
End With
End With
End Sub
May be a bit convoluted, but here is an idea.
Sub f(strSearchFor as string)
Dim r As Excel.Range
Dim d As New Scripting.Dictionary
Set r = Range("a1:b10")
For Each c In r.Columns(2).Cells
If StrComp(c.Value, strSearchFor, vbTextCompare) = 0 Then
If Not d.Exists(c.Value) Then
d.Add c.Offset(0, -1).Value, c.Value
End If
End If
Next c
For Each c In r.Columns(1).Cells
If d.Exists(c.Value) Then
c.Offset(0, 1).Value = d(c.Value)
End If
Next c
Set r = Nothing
Set d = Nothing
End Sub
You can add a helper column and do it with a formula only:
Add the following formula eg. in H2 (of your example) and pull it down:
=IF(COUNTIFS(D:D,D2,G:G,"Good")>0,"Good",G2)
You could try:
Option Explicit
Sub trst()
Dim i As Long, y As Long, LastRow As Long
Dim ID As String, Status As String
With ThisWorkbook.Worksheets("Sheet1") '<- Change Workbook / Sheet names
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRow
ID = .Range("D" & i).Value
Status = .Range("G" & i).Value
For y = 2 To LastRow
If ID = .Range("D" & y).Value Then
.Range("G" & y).Value = Status
End If
Next y
Next i
End With
End Sub
Test with arrais. With arrais it is much faster
Option Explicit
Sub Subst()
With ThisWorkbook.Sheets("Sheet1")
Dim ArrayColumnD As Variant
ArrayColumnD = .Range("D1:D" & .Cells(.Rows.Count, 4).End(xlUp).Row)
Dim ArrayColumnG As Variant
ArrayColumnG = .Range("G1:G" & .Cells(.Rows.Count, 7).End(xlUp).Row)
Dim ID As String
Dim RowActual As Long
Dim RowTest As Long
For RowActual = 2 To UBound(ArrayColumnD)
If ArrayColumnG(RowActual, 1) = "Good" Then
ID = ArrayColumnD(RowActual, 1)
For RowTest = 2 To UBound(ArrayColumnD)
If ArrayColumnD(RowTest, 1) = ID Then
ArrayColumnG(RowTest, 1) = "Good"
End If
Next RowTest
End If
Next RowActual
.Range("G1:G" & .Cells(.Rows.Count, 7).End(xlUp).Row) = ArrayColumnG
End With
End Sub

Format number to be able to search properly

I am trying to format some numbers where some have a leading zero so that I can then search them.
I am needing to format a set of numbers where all are 6 digits and some have a leading zero. I then have a separate code search those numbers for a specific one so the resulting format needs to be searchable. The first code below is the formatting I can't figure out and then the search code. If I simply do an "000000" for formatting I don't believe it works for my search anymore as those now become Special format. Help please?
Sub (First Code)
Dim lngLastRow As Long
lngLastRow = Cells(Rows.Count, "A").End(xlUp).Row
Range("O2:P" & lngLastRow).Select 'specify the range which suits your purpose
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
Dim SUPLCD As Range
Set SUPLCD = Range("Q2:Q")
With Selection
Selection.NumberFormat = "#"
Selection.Value = Format(Selection, "000000")
End With
End Sub
Sub Worksheet()
Dim i As Long
Dim j As Long
Dim wsCurrent As Worksheet
Set wsCurrent = ActiveSheet
Dim wsData As Worksheet
Dim rngData As Range
Set wsData = ThisWorkbook.Worksheets("Tempinterior")
Dim wsTempinterior As Worksheet
' Note that .Add will activate the new sheet so we'll
' need to reactivate the worksheet that was previously active
Set wsTempinterior = Worksheets.Add
wsTempinterior.Name = "copy"
' Find the used range in columns A to K and copy over starting
' at cell A1 of wsGalreq
Set rngData = Intersect(wsData.UsedRange, wsData.Range("A:M"))
' Copy over the first row containing column headers
j = 1
rngData.Rows(1).Copy Destination:=wsTempinterior.Cells(j, 1)
For i = 2 To rngData.Rows.Count
' Check cell of column 10 of row i and copy if matched
If rngData.Cells(i, 10).Value = "026572" Or rngData.Cells(i, 10).Value = "435740" Or rngData.Cells(i, 10).Value = "622639" Then
' Copy over to wsDalreq from row j
j = j + 1
rngData.Rows(i).Copy Destination:=wsTempinterior.Cells(j, 1)
End If
Next
End Sub
With above code, the search doesn't pull the entries with those numbers I think because they are formatted as Special.
You don't have to format Col Q to add a 0, you can accomplish your task with out formatting by using Like in your If statement. Because you are not clear about where the values are, you are formatting Col Q but searching Col J, I used Col Q.
Dim wsData As Worksheet
Set wsData = ThisWorkbook.Worksheets("Sheet1") '("Tempinterior")
Dim rngData As Range
Set rngData = Intersect(wsData.UsedRange, wsData.Range("A:M"))
Sheets.Add(After:=Sheets(Sheets.Count)).Name = "copy"
j = 1
rngData.Rows(1).Copy Destination:=Sheets("copy").Cells(j, 1) 'copy headers for rngData
For i = 2 To rngData.Rows.Count
If wsData.Cells(i, 17).Value Like "26572" Or Sheet1.Cells(i, 17).Value = "435740" Or _
Sheet1.Cells(i, 17).Value = "622639" Then
j = j + 1
rngData.Rows(i).Copy Destination:=Sheets("Copy").Cells(j, 1)
End If
Next i
End Sub
First avoid .Select and you will need to loop the change:
Sub first()
Dim lngLastRow As Long
With Worksheets("Sheet1") 'Change to your sheet
lngLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
With .Range("O2:P" & lngLastRow) 'specify the range which suits your purpose
.NumberFormat = "General"
.Value = .Value
End With
Dim SUPLCD As Range
Set SUPLCD = .Range("Q2:Q" & lngLastRow)
Dim rng As Range
For Each rng In SUPLCD
rng.NumberFormat = "#"
rng.Value = Format(rng.Value, "000000")
Next rng
End With
End Sub

Delete blank cells in a column

The following code converts a table of values to a single column.
The problem is, with my table the number of rows in each column decreases by one for each successive column. Similar to the table shown below.
I am VERY new to writing code and only know the very basics. I copied a script found online to convert a range of values to a single column. The portion of code that I wrote to delete any blank cells is slowing the code tremendously. To convert around 250,000 points to a column is taking roughly 9 hours. I am hoping to reduce the processing time as this is a script I expect to use regularly.
Sub CombineColumns()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim rng As Range
Dim iCol As Long
Dim lastCell As Long
Dim K As Long
K = 484
'set K equal to the number of data points that created the range
Set rng = ActiveCell.CurrentRegion
lastCell = rng.Columns(1).Rows.count + 1
For iCol = 2 To rng.Columns.count
Range(Cells(1, iCol), Cells(rng.Columns(iCol).Rows.count, iCol)).Cut
ActiveSheet.Paste Destination:=Cells(lastCell, 1)
lastCell = lastCell + rng.Columns(iCol).Rows.count
Next iCol
Dim z As Long
Dim m As Long
z = K ^ 2
For Row = z To 1 Step -1
If Cells(Row, 1) = 0 Then
Range("A" & Row).Delete Shift:=xlUp
Application.StatusBar = "Progress: " & Row & " of z: " & Format((z - Row) / z, "Percent")
DoEvents
End If
Next
Application.StatusBar = False
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Sample Table Structure
Because I gave errant information on where this should be posted.
The following code will do what you want nearly instantly.
I used arrays to limit the number of interactions with the worksheet.
Sub foo5()
Dim ws As Worksheet
Dim rng() As Variant
Dim oarr() As Variant
Dim i&, j&, k&
Set ws = ThisWorkbook.Worksheets("Sheet19") 'Change to your sheet
With ws
rng = .Range("A1", .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, .Cells(1, .Columns.Count).End(xlToLeft))).Value
ReDim oarr(1 To Application.WorksheetFunction.CountA(rng), 1 To 1)
k = 1
For i = LBound(rng, 1) To UBound(rng, 1)
For j = LBound(rng, 2) To UBound(rng, 2)
If rng(i, j) <> "" Then
oarr(k, 1) = rng(i, j)
k = k + 1
End If
Next j
Next i
.Range("A1", .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, .Cells(1, .Columns.Count).End(xlToLeft))).Clear
.Range("A1").Resize(UBound(oarr), 1).Value = oarr
End With
End Sub

Excel 2010 VBA. Concatenate 2 columns from a Sheet and paste them in another

Using Excel 2010, I'm trying to create a script that concatenates two text columns (A and B) from Sheet1 and pastes the result in column A of Sheet2.
The workbook uses an external datasource for loading both columns, so the number of rows is not fixed.
I've tried the following code, but not working. variable lRow is not taking any value.
Sub Concat()
Sheets("Sheet1").Select
Dim lRow As Long
lRow = Range("A" & Rows.count).End(xlUp).Row
For i = 2 To lRow
ActiveWorkbook.Sheets("Sheet2").Cells(i, 1) = Cells(i, 1) & Cells(i, 2)
Next i
End Sub
What am I doing wrong. Thanks for helping!
As to what are you doing wrong, I suggest you use
Sub Concat()
Sheets("Sheet1").Select
Dim lRow As Long, i As Long
Dim rng As Range
Set rng = Range("A" & Rows.Count).End(xlUp)
Debug.Print rng.Address(External:=True)
lRow = rng.Row
For i = 2 To lRow
ActiveWorkbook.Sheets("Sheet2").Cells(i, 1) = Cells(i, 1) & Cells(i, 2)
Next i
End Sub
to see what is going on. I tried exactly what you used and it worked for me (Excel 2010).
Specifying what does "variable lRow is not taking any value" mean would help.
You could also try alternatively
Sub Concat2()
Sheets("Sheet1").Select
Dim lRow As Long, i As Long
Dim rng As Range
Set rng = Range("A2").End(xlDown)
Debug.Print rng.Address(External:=True)
lRow = rng.Row
For i = 2 To lRow
ActiveWorkbook.Sheets("Sheet2").Cells(i, 1) = Cells(i, 1) & Cells(i, 2)
Next i
End Sub
which should give the same result if yo do not have blank cells in the middle of the source column A.
I would advise getting out of the .Select method of XL VBA programming in favor of direct addressing that will not leave you hanging with errors.
Sub Concat()
Dim i As Long, lRow As Long
With Sheets("Sheet1")
lRow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow
Sheets("Sheet2").Cells(i, 1) = .Cells(i, 1) & .Cells(i, 2)
Next i
End With
End Sub
Note the periods (aka . or full stop) that prefix .Cells and .Range. These tell .Cells and .Range that they belong to the worksheet referenced in the With ... End With block; in this example that would be Sheets("Sheet1").
If you have a lot of rows to string together you would be better off creating an array of the values from Sheet1 and processing the concatenation in memory. Split off the concatenated values and return them to Sheet2.
Sub concat2()
Dim c As Long, rws As Long, vCOLab As Variant
With Sheets("Sheet1")
rws = .Range("A2:A" & .Cells(Rows.Count, 1).End(xlUp).Row).Rows.Count
vCOLab = .Range("A2").Resize(rws, 3)
For c = LBound(vCOLab, 1) To UBound(vCOLab, 1)
'Debug.Print vCOLab(c, 1) & vCOLab(c, 2)
vCOLab(c, 3) = vCOLab(c, 1) & vCOLab(c, 2)
Next c
End With
Sheets("Sheet2").Range("A2").Resize(rws, 1) = Application.Index(vCOLab, , 3)
End Sub
When interacting with a worksheet, bulk operations will beat a loop every time; the only question is by how much.

Resources