Excel VBA命名范围用尽引用

时间:2015-05-05 17:13:08

标签: excel vba excel-vba

所以我有一大堆代码,用于创建员工使用的工作表中的数据存档。使这个功能的部分原因是在每张可用数据上命名范围。为了保持数据完整性,我需要将命名范围对象从存档表复制到其副本。命名范围以编程方式构建,并在工作表上按预期运行。我遇到的问题是当我去存档工作表时。这是我用来处理命名范围对象的代码:

For Each n In OldSht.Names
    NamedRangeRefersTo = n.RefersTo
    NamedRange = n.Name
    TrimmedName = Right(n.Name, Len(n.Name) - InStr(1, n.Name, "!", vbTextCompare))
    OldSht.Names(n.Name).Delete
    OldSht.Names.Add Name:=ArchiveNamedRange, RefersTo:=NamedRangeRefersTo
Next n

从n中获取数据的字符串用于将相同的名称对象添加到新工作表中。

我遇到的问题是当命名范围在命中Oldsht.Names.Add时引用范围太大时,它会返回错误1004.我发现它是引用范围的大小搞乱它。我还没有找到确切的触发原因,但是当我在大多数命名范围内使用它时,此代码按原样运行。在具有连接数据类型的大型数据集上,这会产生非常大的命名范围(解释如何在文本中构建范围需要很长时间。它是一组包含超过2000行代码的8个子函数),这导致1004错误。

我感到困惑的是为什么我可以构建命名范围,使用命名范围,并且没有问题地复制命名范围(如果我注释掉有问题的行,它会完美执行但我会丢失数据完整性) 。但是当我将引用的范围转换为代码值时,删除旧的名称引用,然后添加一个新名称(使用不同的名称)并为其指定旧名称的相同引用值,它可能会出现此问题。我不明白这样做会有什么不同,而不仅仅是复制/重命名名称对象。不幸的是,到目前为止我还没有找到解决方法,除了在测试场景中删除数据或使用较小的数据集时,我从来没有找到问题的明确原因。有没有人对我能做什么有任何想法?有没有人知道命名范围如何引用可以创建的足够小的范围,但使用其referto值创建新的命名范围只会在引用大范围时导致错误?

我希望我能提供一些更具体的例子,但遗憾的是,刷新足够的敏感信息以提供重现我的确切场景所需的完整代码将非常困难。任何想法将不胜感激。

按照此处的要求设置ArchiveNamedRange:

If Len(OldSht.Name) > 21 Then
ArchiveShtName = Left(OldSht.Name, 21) & DatePart("m", Date) & DatePart("d", Date) & DatePart("yyyy", Date)
Else
ArchiveShtName = OldSht.Name & DatePart("m", Date) & DatePart("d", Date) & DatePart("yyyy", Date)
End If

ArchiveNamedRange = ArchiveShtName & NameObjectName & "Test"

NameObjectName只是对象类型的名称,并从另一个函数传入。我没有这个名字的问题只是fyi。在最极端的示例中,调试运行时的ArchiveNamedRange值为=" OutageSystemProcedureMMDDYYYYSecurityRedactionTest"所以这个名字可能会达到50,如果事情变得更加疯狂,它可能会超过60个字符,但它不会超过这个或者接近255个字符的限制。最终,我还没有看到ArchiveNamedRange的值无效。它只是一个字符串,它总是有一个值。

编辑 - 通过我的故障排除,我发现我的代码在NamedRangeRefersTo的长度为2075时有效,但在长度为2091时无法工作。因此,在2075个字符和2091个字符之间的某个位置是分配字符串的一个突破点。参考:在命名范围内。

因此,让我们假设由于2080年的某种原因(或者实际上在2075年到2091年之间的任何原因)存在字符限制。当我最初找到并创建这些命名范围时,它们将被赋予范围对象。当我复制范围时,我将复制为字符串。不知何故,当我将一个远程对象传递给RefersTo时:它接受超过2080的字符,但是当我传入一个字符串时它没有。鉴于这是我对大量代码的唯一突破点,我宁愿为此找到解决方法,而不是重新考虑我的存档系统的整个概念。如果我使用范围对象来复制命名范围,则它们的引用将遵循旧工作表。这意味着当我将名称复制到它上面时,可以是" CriticalSystemsTest1"并且参考:" CriticalSystemsTest1!$ A $ 2,..."但是一旦我将其复制并重命名存档工作表(现为CriticalSystems562015),引用就会调整为" CriticalSystems562015Test1!$ A $ 2,..."

因此我必须复制为字符串以避免该问题(它会破坏新工作表上的数据)。我真正需要的是一种创造性的方法来克服我的字符串上的字符限制问题。在新工作表上从头开始重建命名范围也不起作用。所以我想如果有人想知道如何解决这个字符串大小问题或修改字符串的方法同时保持命名范围的功能,那将是惊人的。

这些名称中的每一个都有一个工作表级别的范围,所以如果在RefersTo中只使用单元格地址($ A $ 2)的方式,那么它也不包含工作表引用(SheetName) !),这将是一个潜在的解决方案,但我还没有想出是否可能。

1 个答案:

答案 0 :(得分:1)

作为字符串的范围定义太长的原因是它们中有许多区域。因此,一种解决方法是按区域构建新的Range对象区域。您可以使用每个区域的字符串地址,而不会遇到任何限制,因为每个区域只有一个简短的引用。使用Range.Address获取没有工作表引用的单元格引用,因此您可以在不同工作表上创建新的Range但具有相同的单元格。然后使用Union()加入所有区域,并使用新构建的Range而不是字符串创建新名称:

    Dim i As Long, oldRange As Range, newRange As Range

    Set oldRange = n.RefersToRange
    Set newRange = oldSht.Range(oldRange.Areas(1).Address(External:=False))
    For i = 2 To oldRange.Areas.Count
            Set newRange = Union(newRange, oldSht.Range(oldRange.Areas(i).Address(External:=False)))
    Next i
    oldSht.Names.Add Name:="ArchiveNamedRange", RefersTo:=newRange

几点说明:

对于有许多区域的范围,这是。如果您能够可靠地确定遇到问题的阈值,那么首先可能值得对此进行测试,并且仅在需要时使用此解决方法。

测试时我也遇到了使用Worksheet.Range("some very long string range reference")的问题,因此这个限制并不局限于命名范围。