简体   繁体   English

当前两个单元格为空白时,从列范围中删除所有行

[英]Delete All Rows from column range when first two cells are blank

Im looking for a way to delete all rows if the first two cells in column M (Range specified starting from M6) below a sub total is blank (In this case starting from 392 until 425 has to be deleted).如果小计下方的 M 列(从 M6 开始指定的范围)中的前两个单元格为空白,我正在寻找一种删除所有行的方法(在这种情况下,必须删除从 392 到 425 的)。 Second Screenshot is expected result.第二个屏幕截图是预期的结果。

Previously it works but now it deletes everything and leaves just the top 5 rows of the range.以前它可以工作,但现在它会删除所有内容,只留下范围的前 5 行。

Take note that for example - Row 1.1 in this screenshot is only 2 rows (merged) consisting of 5 rows each in actual.请注意,例如 - 此屏幕截图中的第 1.1 行实际上只有 2 行(合并),每行包含 5 行。

My template consists of 3 rows (merged each consisting of 5 rows each) per section and ending with a row called "Sub total".我的模板每个部分包含 3 行(每行合并,每行包含 5 行),并以名为“Sub total”的行结尾。 So total of 17 rows per section.所以每个部分总共有 17 行。 Each section when data is entered can consist of 2 rows (merged means 10 rows in total) + 1 row "Sub Total" or 1 or 3 with "Sub Total" in the end of that section.输入数据时的每个部分可以包含 2 行(合并意味着总共 10 行)+ 1 行“小计”或 1 或 3 行在该部分的末尾带有“小计”。 Bottom of the sheet 3 rows are to be kept there (Total, Submitted Invoices total, Difference) and can somehow be used as a reference for the blank rows which are in between.工作表的底部将保留 3 行(总计、提交的发票总计、差异),并且可以以某种方式用作中间空白行的参考。

Option Explicit

Sub DeleteRows()

Const Col As String = "M"
Const fRow As Long = 13
Const mcCount As Long = 5

Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, Col).End(xlUp).Row

Dim cCell As Range
Dim r As Long

For r = fRow To lRow - mcCount
    'Debug.Print r
    Set cCell = ws.Cells(r, Col)
    If cCell.MergeArea.Cells.Count = mcCount Then
        If Len(CStr(cCell.Value)) = 0 Then
            cCell.Offset(-1).Resize(lRow - r + 1).EntireRow.Delete
            Exit For
        End If
        r = r + mcCount - 1
    End If
Next r

MsgBox "Rows deleted.", vbInformation

End Sub

删除前

最终结果

I don't think your code is doing what you think it is doing.我不认为你的代码正在做你认为它正在做的事情。

a) I wouldn't search column M for the last row; a) 我不会在 M 列中搜索最后一行; use a column that you know will be populated.使用您知道将被填充的列。 b) I would start the loop at row 6. c) Your code isn't checking the "first two cells in column M"; b)我会在第 6 行开始循环。 c)您的代码没有检查“M 列中的前两个单元格”; I'm not sure what you mean by that, but you're only checking the first cell in M.我不确定你的意思是什么,但你只是检查 M 中的第一个单元格。

I think you'd be far better searching for that integer Item No. as the start of a section and 'Sub Total' as the end of one.我认为您最好搜索该整数项目编号作为部分的开头,并将“小计”作为部分的结尾。 You could then check each cell M in that range to see if any data is present.然后,您可以检查该范围内的每个单元格 M 以查看是否存在任何数据。 You don't mention whether a '0' counts as empty so you might want to test for that too.你没有提到'0'是否算作空,所以你可能也想测试一下。

Skeleton code would be a bit like this:骨架代码有点像这样:

Option Explicit

Public Sub RunMe()
    Dim ws As Worksheet
    Dim rngToCheck As Range, rowToCheck As Range
    Dim startRow As Range
    Dim delRanges As Range
    Dim hasValues As Boolean
    
    'Find the data range - note we're starting from row 6.
    'I'm having to use UsedRange as I don't know what your whole sheet looks like.
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    With ws
        Set rngToCheck = .Range(.Cells(6, "A"), .UsedRange.Cells(.UsedRange.Cells.Count))
    End With
    
    For Each rowToCheck In rngToCheck.Rows
        If IsInteger(rowToCheck.Cells(1, "B").Value) Then 'it's the start of a section.
            Set startRow = rowToCheck
        ElseIf Not startRow Is Nothing Then 'we're in a section.
            If rowToCheck.Cells(1, "C") <> "Sub Total" Then 'it's a target data row.
                If Not IsEmpty(rowToCheck.Cells(1, "M").Value) Then
                    hasValues = True
                End If
            Else ' it's the end of a section.
                If Not hasValues Then 'store the section range in the delete range object.
                    Set delRanges = SafeUnion(delRanges, ws.Range(startRow, rowToCheck))
                End If
                'Reset the flags for a new section.
                Set startRow = Nothing
                hasValues = False
            End If
        End If
    Next
    
    'Delete the ranges.
    'Note that this is irreversible, so I've put a break point in for your testing.
    If Not delRanges Is Nothing Then
        'Remove this line if you're happy.
        delRanges.Worksheet.Activate: delRanges.Select: Stop
        delRanges.EntireRow.Delete
    End If
End Sub

Private Function IsInteger(val As Variant) As Boolean
    If IsEmpty(val) Then Exit Function
    If Not IsNumeric(val) Then Exit Function
    If CLng(val) <> val Then Exit Function
    IsInteger = True
    
End Function

Private Function SafeUnion(rng1 As Range, rng2 As Range) As Range
    If rng1 Is Nothing Then
        Set SafeUnion = rng2
    Else
        Set SafeUnion = Application.Union(rng1, rng2)
    End If
End Function

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM