如何通过VBA在Excel中获取/设置单元格的唯一ID

我想要在Excel数据表中为每个数据行定义一个唯一的ID,以便在向前传递数据时可以使用它,并且在上面添加/删除行时保持不变。

我的想法是使用Range( msdn链接 )的ID属性,

所以,我有一个用户定义的函数(UDF),我放置在每个行获取/设置ID如下:

Dim gNextUniqueId As Integer Public Function rbGetId(ticker As String) On Error GoTo rbGetId_Error Dim currCell As Range 'tried using Application.Caller direct, but gives same error Set currCell = Range(Application.Caller.Address) If currCell.id = "" Then gNextUniqueId = gNextUniqueId + 1 'this line fails no matter what value I set it to. currCell.id = Str(gNextUniqueId) End If rbGetId = ticker & currCell.id Exit Function rbGetId_Error: rbGetId = "!ERROR:" & Err.Description End Function 

但是,这在提到的路线上失败了

“应用程序定义或对象定义的错误”

我想也许是UDF的这些限制之一,但如果我从function区button触发的代码尝试它,我也会得到相同的错误…

任何其他build议如何保持一致的ID – 也许我应该通过我的function区button填充单元格,find没有ID的单元格,并生成/设置单元格的值…

编辑:ant认为,我有工作表保护,但即使在一个解锁的单元格,它仍然失败。 解除工作表解决问题….但我已经使用“保护UserInterFaceOnly:=真正”,这应该让我这样做。 如果我手动允许“编辑对象”时,我保护工作表也可以,但我没有看到一个编程选项 – 我需要调用AutoOpen中的保护function来启用UserInterfaceOnlyfunction…

我想我需要closures/保护我的身份证设置周围 – 假设可以做一个UDF …它似乎不能,因为这是行不通的 – 既没有ActiveSheet.unprotect也没有ActiveWorkbook.unprotect 🙁

提前致谢。 克里斯

好的…

看起来,如果工作表被locking,macros不具有对低级信息(如ID)的写访问权限。

但是,我不认为有可能在UDF中取消保护表单。 按照devise,UDF受到严格限制; 我认为有一个单元格公式控制表单保护会打破单元格公式只影响单元格的公式范例。 有关更多详细信息,请参阅Microsoft网站上的此页面 。

我认为这限制了你的select。 您必须:

  • 放弃表保护
  • 放弃UDF,使用Worksheet_Change事件捕获单元格更改并写入ID
  • 使用将ID写入单元格值的UDF,而不是保存到ID

UDF方法充满了问题,因为您正在尝试使用专门用于计算单元格的东西来在工作表上创build永久标记。

尽pipe如此,下面是一个UDF示例,您可以使用它将“永久”值标记到单元格上,该单元格可以在受保护工作表的未locking单元格上工作。 这一个只适用于单个单元格(虽然它可以适应一个数组公式)。

 Public Function CellMark() Dim currCell As Range Set currCell = Range(Application.Caller.Address) Dim myId As String ' must be text; using .value will cause the formula to be called again ' and create a circular reference myId = currCell.Text If (Trim(myId) = "" Or Trim(myId) = "0") Then myId = "ID-" & Format(CStr(gNextUniqueId), "00000") gNextUniqueId = gNextUniqueId + 1 End If CellMark = myId End Function 

虽然这是相当有缺陷的。 但使用复制或填充框将保留以前的复制值。 只有明确地将单元格设置为新的公式才能起作用。 但是,如果你再次input公式(单击它,敲击ENTER)计算一个新的值 – 这是标准的单元格行为。

我认为Worksheet_Change事件是要走的路,它有更多的纬度。 这是一个简单的例子,更新任何单元格更改的ID。 它可以根据您的特定情况而定制。 此function需要添加到每个工作表的ID设置行为是必需的。

 Private Sub Worksheet_Change(ByVal Target As Range) Dim currCell As Range Set currCell = Target.Cells(1, 1) Dim currId As String currId = currCell.ID If Trim(currCell.ID) = "" Then Target.Parent.Unprotect currCell.ID = CStr(gNextUniqueId) Target.Parent.Protect gNextUniqueId = gNextUniqueId + 1 End If End Sub 

最后一张纸条 在所有情况下,如果您重新打开工作表(至less在您的示例中提供的有限的细节),您的ID计数器将被重置。

希望这可以帮助。

与Ant同步 – 您的代码在Excel 2003 SP3上可以正常工作。

我也可以使用:

 Set currCell = Application.Caller If Application.Caller.ID = "" Then gNextUniqueId = gNextUniqueId + 1 'this line fails no matter what value I set it to. currCell.ID = Str(gNextUniqueId) End If 

啊哈! 我想我有它。

我想你是从一个数组公式中调用它,它只被称为一次全范围。 你不能获得范围的ID – 只有一个单元格。 这解释了为什么Application.Caller.ID失败,因为Range(“A1:B9”).ID生成Application-defined or object-defined error

当您使用Range(Application.Caller.Address)获取“单元格”时,您只需将此错误推迟到currCell.ID行。

我想我们可能会遇到一些问题,但我认为他们正在testing问题,而不是代码本身的问题。 首先,如果您从Cell以外的其他任何地方调用该函数,如直接窗口,其他代码等,则不会设置Application.Caller。 这就是生成你的对象没有发现的错误。 其次,如果您复制/粘贴具有该function的单元格,则您将通过复制/粘贴该ID。 所以无论你粘贴到哪里,输出都将保持不变。 但如果你只是复制文本(而不是单元格),然后粘贴,这将工作正常。 (包括你原来使用的Application.Caller。)

问题是与Application.Caller。

既然你是从用户定义的函数调用它,它会传递给你一个错误的描述。 这是帮助文件中的注释。

备注

该属性返回有关如何调用Visual Basic的信息,如下表所示。

来电者 – 返回值

  • 在单个单元格中input的自定义函数 – 指定该单元格的Range对象
  • 一个自定义函数,它是单元格范围内数组公式的一部分的一个自定义函数 – 指定该单元格范围的Range对象
  • Auto_Open,Auto_Close,Auto_Activate或Auto_Deactivatemacros – 作为文本的文档名称
  • 由OnDoubleClick或OnEntry属性设置的macros – macros应用到的图表对象标识符或单元格引用(如果适用)的名称
  • macros对话框(工具菜单),或者任何上面没有描述的调用者 – #REF! 错误值

由于您是从用户定义的函数调用它,所发生的是Application.Caller正在返回一个错误代码的string到您的范围variablescurCell。 它不会导致你的error handling程序会出错的错误。 之后会发生什么是你参考curCell,它实际上不再是一个范围。 在我的机器上尝试设置curCell = Range(“Error 2023”)。 无论这个对象是什么,它可能不再有一个ID属性,当你试图设置它,它会抛出你的对象错误。

这是我会尝试…

  1. 尝试删除您的error handling程序,并查看VBA是否引发Range(Application.Caller.Address)上的任何exception。 这不能解决它,但它可以指出你在正确的方向。

  2. 无论是通过逻辑或Application.ActiveCell或者你想要做的,直接引用单元格。 例如Range(“A1”)或Cells(1,1)。 Application.Caller.Address似乎不是一个好的select使用。

  3. 尝试使用Option Explicit。 由于Range(Application.Caller.Address)看起来不像是传递一个范围,这是curCell的数据types,所以这可能会使你设置curCell的那一行抛出一个错误。

我发现如果我使用“保护DrawingObjects:= False”保护工作表,UDF可以设置Id。 奇怪。

感谢所有帮助。