【问题标题】:Excel VBA named range running out of space in referstoExcel VBA 命名范围在引用中空间不足
【发布时间】:2015-05-05 17:13:07
【问题描述】:

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

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。我通过弄乱来发现它是引用范围的大小带着它。我还没有找到确切的触发原因,但是当我在大多数命名范围上使用它时,这段代码可以正常工作。在具有连接数据类型的大型数据集上,会导致非常大的命名范围(解释范围是如何以文本构建的需要很长时间。它是一组 8 个子函数,代码超过 2000 行),这导致 1004 错误。

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

我希望我可以提供一些更具体的示例,但不幸的是,很难清理足够的敏感信息以提供重现我的确切场景所必需的完整代码。任何想法将不胜感激。

根据要求,此处设置 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 只是对象类型的名称,是从另一个函数传入的。我对这个名字没有问题,仅供参考。在最极端的示例中,调试运行时的 ArchiveNamedRange 值为 = "OutageSystemProcedureMMDDYYYYSecurityRedactionTest",因此名称可能会达到 50,如果事情变得更疯狂,它可能会超过 60 个字符,但它永远不会超过或接近 255字数限制。最终,我没有看到 ArchiveNamedRange 的值无效。它只是一个字符串,它总是有一个值。

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

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

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

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

【问题讨论】:

  • 您发布的代码有错误吗?您在循环中设置NamedRange,然后使用ArchiveNamedRange,在我们可以看到的代码中,您没有为其分配值。如果没记错的话,我们可以看看你在哪里设置了ArchiveNamedRange 的值吗?
  • 问题已编辑以包含该内容。需要明确的是,相同的代码适用于在引用中使用的较小范围。但是我正在使用的范围不超过命名范围的限制,这可以通过我将它从已经存在和工作的范围中拉出来的事实来例证。为了使旧工作表 NamedRange 存在,这意味着它是在代码中构建的,并且为了使其工作,它不能引用比命名范围可以处理的更大的范围。所以我不确定它为什么会失败。
  • RefersTo 也限制为 255 个字符,但如果它与工作表名称完全限定,则可以返回更长的字符串。我会在循环中扔一个Debug.Print Len(n.RefersTo) 并进行测试。
  • 对不起,如果我叫错了树,但有两件事很奇怪。在循环通过同一个集合 (OldSht.Names) 时,您正在从集合中添加和删除对象。这可能会产生不可预知的结果,从跳过项目到无限循环。此外,您似乎没有在循环内修改 ArchiveNamedRange 的值,因此每次您执行 OldSht.Names.Add 时,它都具有相同的 Name 值。当我这样做时,它只会覆盖以前的命名范围,但它可能会导致您的错误?
  • @aucuparia,我明白你的担忧。这不是我制作的完整循环。我无法粘贴完整的循环,因为我必须清理所有这些代码以使其不违反公司标准(尽管如此愚蠢)。其他一些正在做的事情很难清理,并且实际上无助于解决问题,因为整个问题都与引用有关:被分配在这一行代码上。不过感谢您的关注。

标签: vba excel


【解决方案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") 的问题,所以这个限制并不局限于命名范围。

【讨论】:

  • 这是个好主意!非常感谢!我不得不做一些事情来适应它。我不能直接说 OldRange = n.RefersToRange 而是不得不做 OldRange = OldSht.Range(n.Name) 但其余部分效果很好。非常感谢@aucuparia
猜你喜欢
  • 1970-01-01
  • 2019-12-05
  • 2017-10-01
  • 2019-11-25
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多