Excel VBA宏类型不匹配错误

问题描述 投票:0回答:3

我发现我工作的办公室花了几周时间手动浏览一个Excel电子表格,其中包含一个> 500,000行的数据库,寻找符合特定条件的重复行。在研究之前不能简单地删除重复项,因为单个错误可能会丢失数十万美元的生产损失。我决定简单地标记它们,并且在这种情况下引用原始行将是最佳答案。所以我决定查看宏来看看通过使用简单的宏来节省多少时间。我使用它作为编程学习经验,所以请不要“这是一个= = function()”的答案。

我已经写了一个宏并且改了几次都无济于事(目前大多数情况都在下面)。我想使用String变量,因为无法确定将要检查的单元格中输入了什么。这是我从这个网站尝试,失败和学习(?)的内容:

最初,我尝试声明一个变量,并将一个单元格中的值直接附加到它。例如Dim myString As String Set myString = Cells(x, x).Value然而,我一直遇到对象错误。感谢Michael's回应here,我了解到你必须使用Range变量来使用Set

我的下一个问题是出现“类型不匹配”错误。我正在尝试将存储的变量与另一个存储的变量进行分配和比较,我确信这会导致问题。我最初尝试过Dim myRange As Range, myString As String Set myRange = Cells(x, x).Value myString = myRange。这显然不起作用,所以我尝试使用CStr()“更改为字符串”函数将Range变量转换为我想要的String变量。那就是我被困住的地方。

Sub Duplicate()

'Declare the variables
Dim NSNrange, PNrange, KitIDrange As Range
Dim NSN, PN, KitID As String
Dim NSNCheck, PNCheck, KitIDCheck As String
Dim i, j, printColumn, rowCount As Integer

'Set which column we want to print duplicates on, and count the number of rows used
rowCount = ActiveSheet.UsedRange.Rows.Count
printColumn = 9

'Lets get started!

'Clear the duplicate list column for a fresh start
Columns(printColumn).EntireColumn.Delete

'Start on line 2, and grab the cell values for the NSN, Part number and kit ID.
For i = 2 To rowCount

   Set NSNrange = Cells(i, 5).Value
   Set PNrange = Cells(i, 7).Value
   Set KitIDrange = Cells(i, 2).Value

   'Change whatever is contained in those cells into a string and store them into their respective containers
   NSN = CStr(NSNrange)
   PN = CStr(PNrange)
   KitID = CStr(KitIDrange)


      'Now let's look through the rest of the sheet and find any others that match the 3 variables that we stored above
      For j = 2 To rowCount

      'To avoid needless checks, we'll check to see if it's already had a duplicate found. If so, we'll just skip to the next row
      If Cells(j, printColumn).Value = "" Then

      'If the print column is blank, we'll grab the 3 values from the current row to compare against the above variables
      Set NSNrange = Cells(j, 5).Value
      Set PNrange = Cells(j, 7).Value
      Set KitIDrange = Cells(j, 2).Value

      'Now we store the contents into their very own container
      NSNCheck = CStr(NSNrange)
      PNCheck = CStr(PNrange)
      KitIDCheck = CStr(KitIDrange)

         'Check the initial row with the current row to see if the contents match. If so, print which row it is duplicated on.
         If NSN = NSNCheck And PN = PNCheck And KitID = KitIDCheck Then Cells(j, printColumn).Value = "Duplicated on row " & i


        End If

        Next j


   Next i

MsgBox "Search Complete"

End Sub
excel vba excel-vba type-mismatch
3个回答
1
投票

当您询问有关类型错误的注释时。有很多地方可能出现混乱

1)你在同一行上做多个声明的每一行都是这样的:

Dim NSNrange, PNrange, KitIDrange As Range

只有最后一个变量是显式类型声明的(在本例中为Range)。其他是隐含的Variant。所以,我已经完成并单独划线并宣布它们,因为我相信你可能意味着它们。

2)使用Activesheet,在其他地方,只有CellsRange,隐含地引用Activesheet,意味着如果你已经改变了纸张,那么你可能会更长时间地指你想要的纸张。因此,虽然我保留了Activesheet,并使用了一个总体的With Activesheet声明,然后允许我说.Cells.Range等,你应该改为使用显式的工作表名称。

3)无论你使用Set关键字,期望是你正在使用一个对象(例如Range)。按照你的命名惯例,我会说你的意思

Set NSNrange = Cells(i, 5)   

当你说

Set NSNrange = Cells(i, 5).Value

这将范围设置为另一个范围而不是单元格值。

4)我已将整数更改为Longs。您正在使用的行可以超出Integer类型可以处理的行,因此您可能会溢出。 Long更安全。

5)而不是如下在Range上进行转换

NSN = CStr(NSNrange)

如果你想要一个字符串,你可以删除.Value转换,只需要获取CStr属性,它将为你提供所需的字符串。

6)而不是空字符串文字.Text比较,我使用""更快分配和检查。

vbNullString

0
投票

因此,使用Option Explicit Sub Duplicate() Dim NSNrange As Range Dim PNrange As Range Dim KitIDrange As Range Dim NSN As String Dim PN As String Dim KitID As String Dim NSNCheck As String Dim PNCheck As String Dim KitIDCheck As String Dim i As Long Dim j As Long Dim printColumn As Long Dim rowCount As Long With ActiveSheet rowCount = .UsedRange.Rows.Count printColumn = 9 .Columns(printColumn).EntireColumn.Delete For i = 2 To rowCount Set NSNrange = .Cells(i, 5) Set PNrange = .Cells(i, 7) Set KitIDrange = .Cells(i, 2) NSN = NSNrange.Text PN = PNrange.Text KitID = KitIDrange.Text For j = 2 To rowCount If .Cells(j, printColumn).Value = vbNullString Then Set NSNrange = .Cells(j, 5) Set PNrange = .Cells(j, 7) Set KitIDrange = .Cells(j, 2) NSNCheck = NSNrange.Text PNCheck = PNrange.Text KitIDCheck = KitIDrange.Text If NSN = NSNCheck And PN = PNCheck And KitID = KitIDCheck Then .Cells(j, printColumn).Value = "Duplicated on row " & i End If End If Next j Next i End With MsgBox "Search Complete" End Sub (不仅仅是set)分配对象是正确的。 range是一个对象,可以分配给cell变量。但是当你使用对象的方法和属性时,在这种情况下range,并不意味着返回值是一个.Value对象。

因此,如果您需要了解所有属性和方法,我强烈推荐qazxsw poi。

所以当你使用range时,你会得到一个变量(取决于值的类型)。在您的用例中,您可以将其分配给microsoft documentation,即.Value。如果你只想要stringas一个你可以参考的对象:Dim str as string: str = Cells(1,1).Value。现在可以解决所有属性和方法,例如:cell而不是Dim cell as Range: Set cell = Cells(1,1)

还有一些有用的知识。在VBA不像VB.Net,你最好不要混淆,如果你cell.Value只有Cells(1,1).ValueDim var1, var2 as Stringvar2string。因此需要为每个变量var1指定类型。

您可能想要改变的另一件事是将variant分配给特定的Dim var1 as String, var2 as String。根据您的代码所在的模块,您可能会在错误的工作表上运行代码。 (当其他人调整/运行代码时,它最大限度地减少了错误),但主要是你只需要改变一个变量,如果你想引用另一个Cells, Range。可以使用Worksheet完成。

Worksheet

另请注意,这里的对象是没有Worksheet-ObjectDim ws as Worksheet Dim str as String Set ws = Worksheets(1) 'Now adress methods and properties with ws str = ws.Cells(1,1).Value Worksheet是当前sWorksheets的集合。


0
投票

您还可以使用RemoveDuplicates方法。

Worksheet
© www.soinside.com 2019 - 2024. All rights reserved.