3

First post all, so forgive any syntax errors: I've been working on a spreadsheet at work for a long time. Its purpose is to log my calls, as I work in a high volume inbound guest services call center. Sometimes I need to follow up with my guests.

Worksheet is Column A:K, starting at Row 5

Ultimately I'm coding a program to check my records, ignore any row that has data in Column K, then when it finds valid data, copy the records to another sheet, and come back to the main sheet. That part works fine and here is the code for that:

Sub Button2_Click()

Dim sourceEmptyRow As Long
Dim targetEmptyRow As Long
Dim sourceRange As Range
Dim targetRange As Range


'Make Today active
 Sheet1.Activate

'Set Variables
 sourceEmptyRow = FindNextEmpty(Range("K5")).Row
 Set sourceRange = Rows(sourceEmptyRow)
 sourceRange.Copy

'Activate Next Sheet
 sheetQ4.Activate

'Set Variables
 targetEmptyRow = FindNextEmpty(Range("A1")).Row
 Set targetRange = Rows(targetEmptyRow)

 targetRange.PasteSpecial
 Sheet1.Activate
 sourceRange.Delete Shift:=xlUp

End Sub

Here is the FindNextEmpty() function (which I'm pretty sure I found here)

Public Function FindNextEmpty(ByVal rCell As Range) As Range
'Finds the first empty cell downwards in a column.

On Error GoTo ErrorHandle

With rCell
   'If the start cell is empty it is the first empty cell.
   If Len(.Formula) = 0 Then
      Set FindNextEmpty = rCell
      'If the cell just below is empty
   ElseIf Len(.Offset(1, 0).Formula) = 0 Then
      Set FindNextEmpty = .Offset(1, 0)
   Else
      'Finds the last cell with content.
      '.End(xlDown) is like pressing CTRL + arrow down.
      Set FindNextEmpty = .End(xlDown).Offset(1, 0)
   End If
End With

Exit Function
ErrorHandle:
MsgBox Err.Description & ", Function FindNextEmpty."
End Function

My PROBLEM is that I'd like to be able to execute this code block, then when its done, check the next row...if BOTH Column A and K are blank to STOP, otherwise Loop back to the top and execute it on the next row. If I have a long day, I can sometimes get 20-30 calls and pushing a button 20-30 times is not efficient.

I have not SERIOUSLY coded since about 2003, so I'm an EXTREME novice. Thanks for any help, ideas, insight you can provide.

Here is my Spreadsheet

Spreadsheet I'm working with sanitized for public display

paul bica
  • 10,557
  • 4
  • 23
  • 42
C.Croel
  • 35
  • 7
  • Use [THIS](https://stackoverflow.com/questions/11169445/error-in-finding-last-used-cell-in-vba/11169920#11169920) to find the last cell – Siddharth Rout Sep 30 '17 at 20:46
  • Thank you Siddharth, would you suggest I modify my main Sub with this new knowledge and bypass the Function call entirely? or mess with the Function? – C.Croel Sep 30 '17 at 21:53
  • 1
    I think you wouldn't need the function or even the variable `targetEmptyrow`. This code alone should be able to do the job. `Set targetRange = Rows(Cells(Rows.Count, "A").End(xlUp).Row)`. Same method for the `sourceRange`. – Variatus Oct 01 '17 at 03:26
  • 1
    I agree with @Variatus. You do not need a function for this :) Directly use it in your code. – Siddharth Rout Oct 01 '17 at 03:44
  • Thanks for the help so far @Variatus and Siddharth Rout I'll work on incorporating those changes to run smoother. – C.Croel Oct 01 '17 at 15:40
  • I tested this and while it works fine for `targetRange` it doesn't produce the desire results for `sourceRange`because I have a conditional in Column K and occasionally there are blanks. I'll post a screenshot of my spreadsheet which should help understand a bit more! – C.Croel Oct 01 '17 at 16:08
  • UPDATE: the method described above sadly did NOT work. When tested with `targetRange` it put my data in row 4306, but the next row SHOULD have been 1903 – C.Croel Oct 01 '17 at 17:01

1 Answers1

1

This uses the AutoFilter


Option Explicit

Public Sub MoveCompleted()
    Const COL_K = 11
    Const TOP_ROW = 5
    Dim ws1 As Worksheet:   Set ws1 = sheetToday    '<--- Source sheet
    Dim ws2 As Worksheet:   Set ws2 = sheetQ118     '<--- Destination sheet
    Dim maxRows As Long, ws1ur As Range

    optimizeXL True
    With ws1.UsedRange
        If ws1.AutoFilterMode Then .AutoFilter
        maxRows = .Rows.Count

        .Offset(TOP_ROW - 2).Resize(maxRows - (TOP_ROW - 2)).AutoFilter 'ur + header row

        .AutoFilter Field:=COL_K, Criteria1:="="    'show only blanks in K
        Set ws1ur = .Offset(TOP_ROW - 1).Resize(maxRows - TOP_ROW + 1, .Columns.Count)

        On Error Resume Next
        Set ws1ur = ws1ur.SpecialCells(xlCellTypeVisible)
        If Err.Number <> 0 Then
            Err.Clear
        Else
            ws1ur.Copy ws2.Cells(Rows.Count, 1).End(xlUp).Offset(1)
            ws1ur.EntireRow.Delete
        End If
        On Error GoTo 0
        .AutoFilter Field:=COL_K
    End With
    optimizeXL False
End Sub

Public Sub optimizeXL(Optional ByVal settingsOff As Boolean = True)
    With Application
        .ScreenUpdating = Not settingsOff
        .Calculation = IIf(settingsOff, xlCalculationManual, xlCalculationAutomatic)
        .EnableEvents = Not settingsOff
    End With
End Sub

Initial test sheets

Sheet1 Sheet1 sheetQ4 sheetQ4


Result

Sheet1 Sheet1 sheetQ4 sheetQ4

paul bica
  • 10,557
  • 4
  • 23
  • 42
  • 1
    This may be a alternate way for me to do it...and I will defiantly try to apply this technique in another copy of my workbook! I did devise a working solution using some of the techniques given here! I REALLY appreciate all the work you did on this answer! I'm not very good with auto filters yet, so I need to practice/play...this will help! – C.Croel Oct 01 '17 at 23:50
  • If you did get your code working it was probably more effort because you need to check each area of contiguous cells, then move to the next one the same way; that might be ok for a few rows, but the AutoFilter method is much faster. Anyway, I’m glad you worked it out – paul bica Oct 02 '17 at 00:08
  • What lines would I edit/change if I wanted to FLIP the auto filter...Basically the red cells need to stay on Sheet 1, and anything NOT red needs to be moved. – C.Croel Oct 02 '17 at 00:24
  • 1
    That worked like a charm! All I had to do was change `.AutoFilter Field:=COL_K, Criteria1:="<>"` to `.AutoFilter Field:=COL_K, Criteria1:=""` and it worked as I needed! Perfect Solution! – C.Croel Oct 02 '17 at 01:30
  • You got it! I also updated the answer and improved error handling – paul bica Oct 02 '17 at 01:43
  • Good morning, seem to be having a small challenge now. Been using this for a couple days and while its working to remove the old data, it doesn't seem to be putting it anywhere. almost seem like its missing a command somewhere in here: `Else ws1ur.Copy ws2.Cells(Rows.Count, 1).End(xlUp).Offset(1) ws1ur.EntireRow.Delete End If` I can't seem to find the "hey paste what you just copied over here. I've also changed the Sheet names. so "Sheet1" has been renamed "sheetToday" and the place to drop stuff "SheetQ4" was replaced with "sheetQ118" – C.Croel Oct 04 '17 at 13:51
  • 1
    The problem was caused by the new sheet names so I updated the answer. I'm guessing you renamed the CodeName of both sheets (inside the VBA Editor). There are 3 ways to refer to the sheets - see the Edit part of [this answer](https://stackoverflow.com/a/46207885/4914662) to get more details. If you renamed the Tab you can use something like `Set ws1 = ThisWorkbook.Worksheets("sheetToday")` for the source, and `Set ws2 = ThisWorkbook.Worksheets("sheetQ118")` for destination sheet – paul bica Oct 04 '17 at 15:37
  • I did change it in the VBA Editor on the Properties tab. I'll try the longer more explicit references above and see how it works – C.Croel Oct 04 '17 at 17:14
  • Getting `Run-time error '9': Subscript out of range` on the `set` Statements – C.Croel Oct 04 '17 at 17:17
  • UPDATE: Its pasting the data, however, it was not putting it on the next open row...its pasting down in row 600 something...doing some further testing – C.Croel Oct 04 '17 at 17:50
  • That means there is some hidden character, like an empty space (" ") in the cell above A600. The code determines the last row by going all the way down to the last row, and moving up to the first cell containing any data. You can simulate it manually by selecting the last cell in column A (A1048576) and pressing Ctrl + Up Arrow. To remove the extra rows select the first empty row (click the row number to select the entire row) then press Ctrl + Shift + Down Arrow 2 or 3 rimes until all empty rows are selected down to 1048576, then right-click one of the selected rows and select Delete – paul bica Oct 05 '17 at 02:35
  • An easier way to delete extra rows is to use this: `sheetQ118.Range("A20:A1048576").EntireRow.Delete` (just replace A**20** with the first row that is supposed to be empty) – paul bica Oct 05 '17 at 02:40