validation与否?

我正在从用户的input,我给他的select..例如,在列“指挥”他给了一个select“铝或铜”

同样在“绝缘体”栏中,他给出了select“XLPE或PVC”

现在上面的两个是我给用户的简单版本的列表,但是我的一些列表依赖于之前的input,为此我使用了datavalidation:

=indirect($C5 & "_" & $D5) 

(例如:al_xlpe的命名范围)

假设列C和D引用了一些input(这将导致2个!命名范围被定义在前面)。

由于上述方法,我不得不使用大量的命名范围(我的一些validation列表select取决于超过4个或更多的input,他们是这样的:

 =indirect("col6" & "_" & col7 & "_" & col8 & "_" & col9) 

(另一个命名的范围例如:al_xlpe_duct_3;可以有4个这样的)

我正面临着几个问题:

  1. 由于数据库可以随时扩展validation列表,超过4个input将需要4! 命名范围变化。
  2. 数据validation很容易丢失(一个主要问题)
  3. 我不能限制复制和粘贴,因为我的大多数用户将粘贴来自其他工作表的数据(无法使用导入,因为列永远不会被修复)
  4. 我不能使用列表框,因为任何数量的行数据可以input,我需要在每一行中的select
  5. 无法使用MS Access进行数据库pipe理,因为我的工具types对input数据起作用,而且大多数用户不熟悉访问(而且它不允许轻松复制粘贴数据)

有更好的方法吗?

在这个答案中,我提供了一个技术,当我作为一个程序员开始工作45年的时候非常受欢迎,但是除了我自己以外,任何人在很多年以前都没有看到过这个技术。 我们从编译器开发中借用了这个技术,但是使用起来却不太正式。

在全面的技术,将有五个步骤:

  1. devise一种以对人类方便的方式对规范进行编码的方法。
  2. 编码规范。
  3. devise一个或多个表格来保存规格,方便快速处理。
  4. devise和实现一个程序,将人格转换为快速处理格式。
  5. devise并实现一个程序来解释快速处理格式并执行所需的操作。

对于每一个问题,并不是所有的五步都是必需的 有时人和快速处理的格式可能是一样的。 这听起来很复杂,但它使我们能够轻松高效地解决许多复杂的问题。

在下面的工作表中,我编码了我对你需要的validationtypes的理解。

  | A | B | C | --+--------------------+--------------------+--------------------+ 1|Permitted |Conditions --------------> | 2|C=V1|V2|V3|V4 | | | 3|D=V5 |C=V1|V2 | | 4|D=V6 |C=V3|V4 | | 5|E=V7|V8 |D=V5 |C=V1 | 6|E=V9|V10 |D=V5 |C=V2 | 7|E=V11|V12 |D=V6 |C=V3 | 8|E=V13|V14 |D=V6 |C=V4 | 

在第2行中,我声明C列中的单元格可能取值为V1或V2或V3或V4。

在第3行中,我声明D列中的一个单元格可能取值为V5,但是只有同一行的C列的值为V1或V2。

在第4行中,我为D列中的单元格声明了一个具有自己的一组条件的另一个值。

在第5行中,我声明E列中的单元格可能取值为V7或V8,但是只有同一行的列D的值为V5,并且行的列C的值为V1。

我对您的要求没有足够的了解,不知道这是否是您的validation要求的最佳或完整表示。 不过,如果你喜欢这种技术,我希望你能明白,并且可以开发一个你的需求的方便表示。

接下来我需要定义这个规范的快速处理forms。 我devise了四个表格,并实现了下面的代码,将人工表格格式转换为快速处理格式,然后将这些表格的内容输出到即时窗口,准备放置在这个答案中:

 Rules per Column table C RR RR = Column First rule Last rule 3 1 1 4 2 3 5 4 7 

在工作表中有三列有validation规则,列3(C),4(D)和5(E)。 上表告诉我们,第3栏(C)适用规则1至1,第5栏(E)适用规则4至7。

 Rule table I VV VV CC CC = Index First value Last value First condition Last condition 1 1 4 1 0 2 5 5 1 1 3 8 8 2 2 4 11 12 3 4 5 15 16 5 6 6 19 20 7 8 7 23 24 9 10 

对于规则1,条件1至0适用,即没有条件。 允许的值是值表中的条目1到4(V1,V2,V3和V4)。 这对应于工作表中的第2行。

对于规则4,允许的值是提供条件3至4的值表中的条目11和12(V7和V8)。 条件3是列4(D)必须等于值表中的条目13(V5)。 条件4是列3(C)必须等于值表中的条目14(V1)。 这对应于工作表中的第5行。

 Condition table IC VV VV = Index Column First value Last value 1 3 6 7 2 3 9 10 3 4 13 13 4 3 14 14 5 4 17 17 6 3 18 18 7 4 21 21 8 3 22 22 9 4 25 25 10 3 26 26 Value table Entries 1 to 26 E 1=V1 E 2=V2 E 3=V3 E 4=V4 E 5=V5 E 6=V1 E 7=V2 E 8=V6 E 9=V3 E10=V4 E11=V7 E12=V8 E13=V5 E14=V1 E15=V9 E16=V10 E17=V5 E18=V2 E19=V11 E20=V12 E21=V6 E22=V3 E23=V13 E24=V14 E25=V6 E26=V4 

如果你不习惯考虑通过链接表来控制代码,这可能需要一点时间来充分理解。 我遵循了几条规则的链接。 再尝试一下,你会明白的。 请注意,工作表是如何devise的,以便于人类进行维护,而这些表格是为计算机快速执行而devise的。

此编译过程可以在Worksheet Open例程中,也可以预编译并将表存储在工作簿中。 这些表已准备好通过“工作表更改”例程执行,也可以用于计算公式并将其放置在适当的单元格中。

我希望我已经解释得很清楚了,以便你明白这个想法,并决定这个技术是否适合你的问题。 如有必要,可以回答问题,我将扩大解释。

以下代码将人类格式转换为快速处理格式,然后将快速处理格式输出到即时窗口。

 Option Explicit Type typColRule ' Definition of entry in Rules per Column table InxRule1 As Long ' Index of first rule for this column. ) InxRule1 > InxRuleL InxRuleL As Long ' Index of last rule for this column. ) if no rules for column End Type Type typRule ' Definition of Rule table InxValue1 As Long ' Index of first permitted value for this rule InxValueL As Long ' Index of last permitted value for this rule InxCond1 As Long ' Index of first condition for this column. ) InxCond1 > InxCondL InxCondL As Long ' Index of last rule for this column. ) if no rules for column End Type Type typCond ' Definition of Condition table Col As Long ' Column to which this condition applies InxValue1 As Long ' Index of first permitted value for this condition InxValueL As Long ' Index of last permitted value for this condition End Type ' ColRule is sized to (Min to Max) where Min is the lowest column validated ' and Max is the highest column validated. ColRule(N).InxRule1 identifies ' the first rule in Rule for column N. ColRule(N).InsRuleL identifies the ' last rule in Rule for column N. Dim ColRule() As typColRule ' There is one entry in Rule per validation row in worksheet "Validate". Dim Rule() As typRule ' There is one entry in ValueCell per value referenced in a permitted or ' a condition. Dim ValueCell() As String ' There is one entry in Cond per condition in worksheet "Validate" Dim Cond() As typCond Sub CompileValidation() Dim ColCodeCrnt As String Dim ColNumCrnt As String Dim ColValCrnt As Long Dim ColValidateCrnt As Long Dim ColValMin As Long Dim ColValMax As Long Dim ConditionCrnt As String Dim InxCondCrnt As Long Dim InxRuleCrnt As Long Dim InxValueCellCrnt As Long Dim InxValueListCrnt As Long Dim NumCond As Long Dim NumValue As Long Dim PermittedCrnt As String Dim PosEqual As Long Dim RowValidateCrnt As Long Dim ValueList() As String With Worksheets("Validate") ' Determine the size of the arrays to which information will be ' compiled. Find ' * The minimum and maximum columns subject to validated ' * Number of conditions ' * Number of values references ' This routine does not allow for blank rows or columns in the ' middle of worksheet "Validate". ColValMin = -1 ColValMax = -1 NumCond = 0 NumValue = 0 RowValidateCrnt = 2 Do While True PermittedCrnt = .Cells(RowValidateCrnt, 1).Value If PermittedCrnt = "" Then Exit Do End If PosEqual = InStr(1, PermittedCrnt, "=") Debug.Assert PosEqual > 1 ' Determine range of columns validated ColCodeCrnt = Mid(PermittedCrnt, 1, PosEqual - 1) ColNumCrnt = Range(ColCodeCrnt & "1").Column If ColValMin = -1 Then ColValMin = ColNumCrnt ElseIf ColValMin > ColNumCrnt Then ColValMin = ColNumCrnt End If If ColValMax = -1 Then ColValMax = ColNumCrnt ElseIf ColValMax < ColNumCrnt Then ColValMax = ColNumCrnt End If ' Determine number of conditions and number of values ValueList = Split(Mid(PermittedCrnt, PosEqual + 1), "|") NumValue = NumValue + UBound(ValueList) - LBound(ValueList) + 1 ColValidateCrnt = 2 Do While True ConditionCrnt = .Cells(RowValidateCrnt, ColValidateCrnt).Value If ConditionCrnt = "" Then Exit Do End If PosEqual = InStr(1, ConditionCrnt, "=") Debug.Assert PosEqual > 1 ValueList = Split(Mid(ConditionCrnt, PosEqual + 1), "|") NumValue = NumValue + UBound(ValueList) - LBound(ValueList) + 1 ColValidateCrnt = ColValidateCrnt + 1 Loop NumCond = NumCond + ColValidateCrnt - 2 RowValidateCrnt = RowValidateCrnt + 1 Loop ' Size arrays ReDim ColRule(ColValMin To ColValMax) ReDim Rule(1 To RowValidateCrnt - 2) ReDim ValueCell(1 To NumValue) ReDim Cond(1 To NumCond) InxRuleCrnt = 0 InxValueCellCrnt = 0 InxCondCrnt = 0 ' Extract rules in column number order For ColValCrnt = ColValMin To ColValMax ' The first rule for this column, if any, will be the ' next entry in the Rule table ColRule(ColValCrnt).InxRule1 = InxRuleCrnt + 1 ' If there are no rules for this column, the last rule index ' will be less than the first rule undex ColRule(ColValCrnt).InxRuleL = InxRuleCrnt RowValidateCrnt = 2 Do While True PermittedCrnt = .Cells(RowValidateCrnt, 1).Value If PermittedCrnt = "" Then Exit Do End If PosEqual = InStr(1, PermittedCrnt, "=") ColCodeCrnt = Mid(PermittedCrnt, 1, PosEqual - 1) ColNumCrnt = Range(ColCodeCrnt & "1").Column If ColNumCrnt = ColValCrnt Then ' This rule is for the current column InxRuleCrnt = InxRuleCrnt + 1 ' This could be the last rule for this column so ' store its index against the column ColRule(ColValCrnt).InxRuleL = InxRuleCrnt ' The first value for this rule will be the next ' entry in the Value table Rule(InxRuleCrnt).InxValue1 = InxValueCellCrnt + 1 ValueList = Split(Mid(PermittedCrnt, PosEqual + 1), "|") ' Save each permitted value in the Value table For InxValueListCrnt = LBound(ValueList) To UBound(ValueList) InxValueCellCrnt = InxValueCellCrnt + 1 ValueCell(InxValueCellCrnt) = ValueList(InxValueListCrnt) Next ' Record the index of the last permitted value for this rule Rule(InxRuleCrnt).InxValueL = InxValueCellCrnt ' The first condition for this rule, if any, will be the next ' entry in the Condition table Rule(InxRuleCrnt).InxCond1 = InxCondCrnt + 1 ' If there are no conditions for this rule, the last condition ' index will be less than the first condition undex Rule(InxRuleCrnt).InxCondL = InxCondCrnt ColValidateCrnt = 2 Do While True ConditionCrnt = .Cells(RowValidateCrnt, ColValidateCrnt).Value If ConditionCrnt = "" Then Exit Do End If InxCondCrnt = InxCondCrnt + 1 PosEqual = InStr(1, ConditionCrnt, "=") ColCodeCrnt = Mid(ConditionCrnt, 1, PosEqual - 1) ColNumCrnt = Range(ColCodeCrnt & "1").Column ' Store the column for this condition Cond(InxCondCrnt).Col = ColNumCrnt ' The first value for this condition will be the next ' entry in the Value table Cond(InxCondCrnt).InxValue1 = InxValueCellCrnt + 1 ValueList = Split(Mid(ConditionCrnt, PosEqual + 1), "|") For InxValueListCrnt = LBound(ValueList) To UBound(ValueList) InxValueCellCrnt = InxValueCellCrnt + 1 ValueCell(InxValueCellCrnt) = ValueList(InxValueListCrnt) Next ' Record last value for this condition Cond(InxCondCrnt).InxValueL = InxValueCellCrnt ColValidateCrnt = ColValidateCrnt + 1 Loop ' Record last condition for this rule Rule(InxRuleCrnt).InxCondL = InxCondCrnt End If RowValidateCrnt = RowValidateCrnt + 1 Loop Next End With Debug.Print " Rules per Column table" Debug.Print " C RR RR" For ColValCrnt = ColValMin To ColValMax Debug.Print " " & ColValCrnt & " " & _ Right(" " & ColRule(ColValCrnt).InxRule1, 2) & " " & _ Right(" " & ColRule(ColValCrnt).InxRuleL, 2) Next Debug.Print Debug.Print " Rule table" Debug.Print " I VV VV CC CC" For InxRuleCrnt = 1 To UBound(Rule) Debug.Print " " & InxRuleCrnt & " " & _ Right(" " & Rule(InxRuleCrnt).InxValue1, 2) & " " & _ Right(" " & Rule(InxRuleCrnt).InxValueL, 2) & " " & _ Right(" " & Rule(InxRuleCrnt).InxCond1, 2) & " " & _ Right(" " & Rule(InxRuleCrnt).InxCondL, 2) & " " Next Debug.Print Debug.Print " Condition table" Debug.Print " IC VV VV" For InxCondCrnt = 1 To UBound(Cond) Debug.Print " " & Right(" " & InxCondCrnt, 2) & " " & _ Cond(InxCondCrnt).Col & " " & _ Right(" " & Cond(InxCondCrnt).InxValue1, 2) & " " & _ Right(" " & Cond(InxCondCrnt).InxValueL, 2) Next Debug.Print Debug.Print " Value table" Debug.Print " "; For InxValueCellCrnt = 1 To UBound(ValueCell) Debug.Print "E" & Right(" " & InxValueCellCrnt, 2) & "=" & _ Left(ValueCell(InxValueCellCrnt) & " ", 5); If (InxValueCellCrnt Mod 10) = 0 Then Debug.Print Debug.Print " "; End If Next 

结束小组

如果您要坚持命名范围,则应使用INDEX和COUNTA公式使命名范围dynamic化。 这样您可以将logging添加到列表中,并且命名的范围将自动调整。 但接下来我会告诉你不要使用命名的范围。

这种链接的数据validation对于简单的链表是很好的。 但是,你的情况是非常简单的,我想你需要从DV和ActiveX控件,可能在用户窗体。

有几个级别的复杂性,你可以得到。 一方面是你现在拥有的。 另一方面,所有东西都存放在数据库中,而Excel是一个适合关系数据库的计算引擎/前端。 你可能会在这两个中间结束。

我没有足够的信息给你一个真正相关的,详细的答案,所以我会做一些假设,你不得不承认什么时候它不适合你的情况。 我认为你需要创build一个用户窗体来处理数据录入。 用户表单上的列表框/combobox将通过代码dynamic更新。 用户窗体将通过function区,右键菜单或“编辑”超链接调用。 用户表单将填充当前选定的行。

然后你将有一个复制和粘贴选项。 用户可以将个别项目复制并粘贴到用户表单中,您的代码将对其进行validation。 或者他们可以复制代码将validation的整个信息logging。

不要害怕Access作为后端。 我的大部分项目都是由Excel控制的Jet数据库。 Excel是计算引擎,input机制和报告机制。