【问题标题】:Complex Search and return function in VBAExcelVBA Excel中的复杂搜索和返回函数
【发布时间】:2017-03-17 06:16:11
【问题描述】:

我是 VBA 新手,正在努力寻找解决方案,在这里找不到答案。

我有一个每天都在增长的大型数据库。该数据库由 2 张纸组成。表 1 用于捕获从 A 列到 BF 列的数据。表 2 只是一个收集点,其中填充了从表 1 收集数据的公式。我没有创建这个工作簿/数据库,我认为它的设计不是很好,但这是我必须使用的;并且改变它并不是一个真正的选择。

我需要做的: 我需要创建第三张工作表(已经创建工作表),它会产生以下复杂的搜索...

我需要 1 个单元格作为输入名称的入口点。我需要从第一个条目(位于第 17 行)到最后一个条目(请记住,每天有 20 到 40 个新条目,所以它必须能够在 AO 到 AX 列中搜索该名称的每个实例)成长)。那是容易的部分。

我需要从我的搜索中收到 4 件事。

  1. 名称出现在搜索区域(AO 到 AX 列)的总次数。
  2. 名称出现在4列中的总次数和在其他4列中分别出现的总次数(4列在4个类别中为“通过”,其中4列在相同的4个类别中为“失败”) .
  3. 名称在 8 列中的每一列中出现的总次数
    我可以使用 countifs 做到这一点
  4. (这是我做不到的)。我需要从名称出现的每一行中的 3 个完全不同的列中获取信息。

例如:如果名称出现在 AO 和 AQ 列但在不同的行上(很可能会出现) 我需要从 A、B 和 C 列中获取出现名称的行的信息,然后将该信息复制并粘贴到“计数”信息下方的工作表 3 上。

我可以通过使用隐藏在工作表 1 上的 countifs 函数来完成 1、2 和 3。函数的结果通过使用 =Sheet1!(单元格引用)传递到工作表 3。我希望我输入正确。 countifs 函数引用工作表 3 中的一个单元格。 =COUNTIFS(Sheet1!AU17:AU2500, Sheet3!A1)。这使我可以计算 AU 列是否有任何我在工作表 3 上的 A1 中键​​入的任何实例。通过使用此公式创建 8 列,然后将结果传输到工作表 3,我可以捕获初始数据。

现在,大老板当然希望在 A、B 和 C 列中找到这些名称出现在任何行中的信息。因为“查理”可能出现在 8 列中的任何一个以及当前超过 2000 行中的任何一个,并且可能出现很多次,很明显 VBA 是我最好的解决方案,但是作为 VBA 的新手,我正在努力寻找代码和变量的正确组合。

【问题讨论】:

  • 欢迎来到 StackOverflow。请注意,这不是免费的代码编写服务。然而,我们渴望帮助其他程序员(和有志者)编写自己的代码。请阅读How do I Ask a Good Question 上的帮助主题。您可能还想take the tour 并在这样做的同时获得徽章。之后,请使用您迄今为止编写的 VBA 代码更新您的问题,以完成您希望完成的任务。我们会在这里等你。随时准备协助并帮助您完成您的代码
  • @Ralph。感谢您的评论。我认为我在我的问题上做得很好。我实际上并没有写任何关于这个问题的代码,因为我昨天才开始学习 VBA 并且迷路了。我已经学习了如何选择单元格和更改工作表等的基础知识……但这仍然超出了我的范围。我会继续努力,希望能写出一些可以做某事的代码,但我知道你来这里并不是为了给人们写代码。如果我的问题表明这是我的目标,我深表歉意。

标签: excel vba


【解决方案1】:

让您开始:这是一个通用的 findall 函数,您可以使用它来查找搜索范围内的所有单元格:

Function FindAll(What, _
    Optional SearchWhat As Variant, _
    Optional LookIn, _
    Optional LookAt, _
    Optional SearchOrder, _
    Optional SearchDirection As XlSearchDirection = xlNext, _
    Optional MatchCase As Boolean = False, _
    Optional MatchByte, _
    Optional SearchFormat) As Range

    'LookIn can be xlValues or xlFormulas, _
     LookAt can be xlWhole or xlPart, _
     SearchOrder can be xlByRows or xlByColumns, _
     SearchDirection can be xlNext, xlPrevious, _
     MatchCase, MatchByte, and SearchFormat can be True or False. _
     Before using SearchFormat = True, specify the appropriate settings for the Application.FindFormat _
     object; e.g. Application.FindFormat.NumberFormat = "General;-General;""-"""

    Dim SrcRange As Range
    If IsMissing(SearchWhat) Then
        Set SrcRange = ActiveSheet.UsedRange
    ElseIf TypeOf SearchWhat Is Range Then
        Set SrcRange = IIf(SearchWhat.Cells.Count = 1, SearchWhat.Parent.UsedRange, SearchWhat)
    ElseIf TypeOf SearchWhat Is Worksheet Then
        Set SrcRange = SearchWhat.UsedRange
    Else: SrcRange = ActiveSheet.UsedRange
    End If
    If SrcRange Is Nothing Then Exit Function

    'get the first matching cell in the range first
    With SrcRange.Areas(SrcRange.Areas.Count)
        Dim FirstCell As Range: Set FirstCell = .Cells(.Cells.Count)
    End With

    Dim CurrRange As Range: Set CurrRange = SrcRange.Find(What:=What, After:=FirstCell, LookIn:=LookIn, LookAt:=LookAt, _
        SearchDirection:=SearchDirection, MatchCase:=MatchCase, MatchByte:=MatchByte, SearchFormat:=SearchFormat)

    If Not CurrRange Is Nothing Then
        Set FindAll = CurrRange
        Do
            Set CurrRange = SrcRange.Find(What:=What, After:=CurrRange, LookIn:=LookIn, LookAt:=LookAt, _
            SearchDirection:=SearchDirection, MatchCase:=MatchCase, MatchByte:=MatchByte, SearchFormat:=SearchFormat)
            If CurrRange Is Nothing Then Exit Do
            If Application.Intersect(FindAll, CurrRange) Is Nothing Then
                Set FindAll = Application.Union(FindAll, CurrRange)
            Else: Exit Do
            End If
        Loop
    End If
End Function

找到范围后,您可以遍历范围中的每一行(例如,对于 Rng.Rows 中的每个 rw)并将 A、B 和 C 列中的数据提取到目标工作表。

******编辑******

所以我想我会把代码放在一起,因为提取这些数据有点挑战。我认为以下内容应该适合您...

就目前而言,在工作表 3 的“A1”中输入搜索词,它将使用同一张工作表中从第 2 行开始的数据填充列 B:D。

Sub ExtractData()
    Dim wsSrc As Worksheet: Set wsSrc = Worksheets("Sheet1")
    Dim wsDest As Worksheet: Set wsDest = Worksheets("Sheet3")

    Dim LastRow As Long, RowCounter As Long
    Dim SearchRange As Range, FoundRange As Range, rw As Range
    Dim Val As String: Val = wsDest.Range("A1")

    With wsSrc
        LastRow = .UsedRange.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
        Set SearchRange = .Range("AO17", .Cells(LastRow, "AX")) 'AO-AX
        Set FoundRange = FindAll(Val, SearchRange)
    End With

    'Clear Destination Sheet (except header row)
    With wsDest
        On Error Resume Next
        Application.Intersect(wsDest.UsedRange, wsDest.UsedRange.Offset(1, 0)).ClearContents
        On Error GoTo 0
    End With

    ' Copy Data
    RowCounter = 2
    Set FoundRange = Union(FoundRange, FoundRange.EntireRow.Rows) 'Expand Range to entire rows of Range
    For Each rw In FoundRange.Rows
        wsDest.Cells(RowCounter, 2) = wsSrc.Cells(rw.Row, 1)
        wsDest.Cells(RowCounter, 3) = wsSrc.Cells(rw.Row, 2)
        wsDest.Cells(RowCounter, 4) = wsSrc.Cells(rw.Row, 3)
        RowCounter = RowCounter + 1
    Next rw

End Sub

Function FindAll(What, _
    Optional SearchWhat As Variant, _
    Optional LookIn, _
    Optional LookAt, _
    Optional SearchOrder, _
    Optional SearchDirection As XlSearchDirection = xlNext, _
    Optional MatchCase As Boolean = False, _
    Optional MatchByte, _
    Optional SearchFormat) As Range

    'LookIn can be xlValues or xlFormulas, _
     LookAt can be xlWhole or xlPart, _
     SearchOrder can be xlByRows or xlByColumns, _
     SearchDirection can be xlNext, xlPrevious, _
     MatchCase, MatchByte, and SearchFormat can be True or False. _
     Before using SearchFormat = True, specify the appropriate settings for the Application.FindFormat _
     object; e.g. Application.FindFormat.NumberFormat = "General;-General;""-"""

    Dim SrcRange As Range
    If IsMissing(SearchWhat) Then
        Set SrcRange = ActiveSheet.UsedRange
    ElseIf TypeOf SearchWhat Is Range Then
        Set SrcRange = IIf(SearchWhat.Cells.Count = 1, SearchWhat.Parent.UsedRange, SearchWhat)
    ElseIf TypeOf SearchWhat Is Worksheet Then
        Set SrcRange = SearchWhat.UsedRange
    Else: SrcRange = ActiveSheet.UsedRange
    End If
    If SrcRange Is Nothing Then Exit Function

    'get the first matching cell in the range first
    With SrcRange.Areas(SrcRange.Areas.Count)
        Dim FirstCell As Range: Set FirstCell = .Cells(.Cells.Count)
    End With

    Dim CurrRange As Range: Set CurrRange = SrcRange.Find(What:=What, After:=FirstCell, LookIn:=LookIn, LookAt:=LookAt, _
        SearchDirection:=SearchDirection, MatchCase:=MatchCase, MatchByte:=MatchByte, SearchFormat:=SearchFormat)

    If Not CurrRange Is Nothing Then
        Set FindAll = CurrRange
        Do
            Set CurrRange = SrcRange.Find(What:=What, After:=CurrRange, LookIn:=LookIn, LookAt:=LookAt, _
            SearchDirection:=SearchDirection, MatchCase:=MatchCase, MatchByte:=MatchByte, SearchFormat:=SearchFormat)
            If CurrRange Is Nothing Then Exit Do
            If Application.Intersect(FindAll, CurrRange) Is Nothing Then
                Set FindAll = Application.Union(FindAll, CurrRange)
            Else: Exit Do
            End If
        Loop
    End If
End Function

【讨论】:

  • 谢谢。现在我只需要围绕你所写的内容。我理解其中一些,但我正在努力跟上代码。对于该功能,我是只选择其中一个,还是进行设置以便我可以将所有这些作为可选功能运行?如果是这样,当我尝试更改 _ 时,我会收到一个错误。如何设置“搜索框”的参数?对于所有的混乱,我很抱歉,我是 VBA 的新手。
  • OK,功能如此;它本质上非常类似于 VBA 内置的 Range.Find 函数(谷歌:Excel VBA 查找函数)。除了“什么”之外,其他所有内容都是可选的,因此您不一定需要使用它们。代码中的下划线字符表示代码在下一行继续(它是一个换行符),因此删除它们将破坏函数(但是您可以将它们全部删除并在一行上全部调用函数;我们添加下划线以提高可读性)
  • 感谢您的解释。我会继续努力,希望能有一些代码给大家看,看看我能不能让它工作。
  • 非常感谢您抽出宝贵的时间来做这件事。我现在正在浏览代码以了解它在做什么,以及为什么它正在做它正在做的事情。我非常感谢您解决了我的主要问题。我希望学会自己做这件事。我正在尝试向标准添加一些内容,但我认为我输入错误或输入错误。
  • 您可以随时提出更多问题;因此,如果您将想要实现的目标保留为较小的工作包,那么您将更有可能发布解决方案
猜你喜欢
  • 2015-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
相关资源
最近更新 更多