我正在接受用户的输入,我正在给他选择.. 例如,在“导体”栏中,给予他选择“Al或Cu”
同样,在“绝缘体”栏中,他可以选择“XLPE或PVC”
现在上面两个是我给用户的简单版本的列表,但是我的一些列表依赖于以前的输入,为此我使用了这样的数据验证:
=indirect($C5 & "_" & $D5)
(例如:al_xlpe的命名范围)
假设列C和D引用某些输入(这将导致先前定义2个!命名范围)。
由于上述方法,我被迫使用了很多命名范围(我的一些验证列表选择取决于超过4个或更多输入,它们是这样的:
=indirect("col6" & "_" & col7 & "_" & col8 & "_" & col9)
(例如:al_xlpe_duct_3的另一个命名范围;可以有4个!)
我面临几个问题:
有更好的方法吗?
答案 0 :(得分:1)
在这个答案中,我提供了一种技术,当我作为一名程序员开始工作45年时非常受欢迎,但是除了我自己多年以来,除了我之外,我还没有看到过常规应用。我们从编译器开发中借用了这种技术,但不太正式地使用它。
在完整的技术中,将有五个步骤:
并非每个问题都需要所有五个步骤;有时人类和快速处理格式可能是相同的。这可能听起来很复杂,但它使我们能够轻松有效地解决许多复杂问题。
在下面的工作表中,我编写了我对您需要的验证类型的理解。
| 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时。 / p>
我对您的要求缺乏足够的了解,无法知道这是否是您的验证要求的最佳或完整表示。但是,如果你喜欢这种技术,我希望你能得到这个想法并且可以方便地表达你的要求。
接下来我需要定义此规范的快速处理形式。我设计了四个表,并实现了下面的代码,将人工作表格式转换为快速处理格式,然后将这些表的内容输出到即时窗口,准备放在这个答案中:
Rules per Column table
C RR RR = Column First rule Last rule
3 1 1
4 2 3
5 4 7
工作表中有三列有验证规则,即第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适用,即没有条件。允许的值是Value表中的条目1到4(V1,V2,V3和V4)。这对应于工作表中的第2行。
对于规则4,允许值是值表中的条目11和12(V7和V8),条件3到4适用。条件3是第4列(D)必须等于值表中的条目13(V5)。条件4是列3(C)必须等于值表中的条目14(V1)。这对应于工作表中的第5行。
Condition table
I C 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
如果您不习惯通过链接表控制代码,可能需要一些时间才能完全理解。我已经按照几个规则的链接。再试几次,你就会明白这个想法。请注意工作表是如何设计为易于人类维护的,而这些表是为计算机快速执行而设计的。
此编译过程可以在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 " I C 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
End Sub
答案 1 :(得分:0)
如果您要坚持命名范围,则应使用INDEX和COUNTA公式使命名范围动态化。这样您就可以将记录添加到列表中,并且命名范围将自动调整。但接下来我会告诉你不要使用命名范围。
这种链接数据验证对于简单的链表很有用。但是你的情况已经非常简单了,我认为你需要远离DV和ActiveX控件,可能是用户形式。
您可以达到一定程度的复杂性。一方面是你现在拥有的。另一方面,所有内容都存在于数据库中,Excel是适当关系数据库的计算引擎/前端。你可能会在这两者的中间结束。
我没有足够的信息给你一个真正相关的,详细的答案,所以我会做出一堆假设,你必须认识到它何时不适合你的情况。我认为您需要创建一个userform来处理数据输入。 userform上的列表框/组合框将通过代码动态更新。将通过功能区,右键单击菜单或“编辑”超链接调用用户窗体。 userform将填充当前选定的行。
然后你将有一个复制和粘贴选项。用户可以将单个项目复制并粘贴到用户表单中,您的代码将验证它们。或者他们可以复制代码将验证的整个信息记录。
不要回避Access作为后端。我的大多数项目都是由Excel控制的Jet数据库。 Excel是计算引擎,输入机制和报告机制。