2012-04-30 30 views
3

我正在輸入來自用戶對此我給他的選擇.. 比如,對於列「指揮家」,他被賦予了選擇「爲鋁或銅」驗證與否?

同樣在列「絕緣體」,他被賦予了選擇「交聯聚乙烯或聚氯乙烯」

現在上面兩個是列表我給用戶的簡單版本,但我的一些列表依賴於以前的輸入和我使用這樣的資料驗證:

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

(例如:al_xlpe的命名範圍)

假設列C和D指的是一些輸入(這將導致2!前面定義了命名範圍)。

因爲我已經被迫使用大量的命名範圍的上述方法的(我的一些驗證列表選擇取決於在4倍或更多的投入,他們是這樣的:

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

(另一個名爲範圍如:!al_xlpe_duct_3;可以有4對這些)

有幾個問題,我面對:

  1. 由於數據庫可以由超過4輸入驗證列表隨時展開將需要4!命名範圍變化。
  2. 數據驗證是很容易丟失(一個主要問題)
  3. 我不能限制副本,因爲我的大多數用戶的粘貼將來自其他表粘貼數據(不能使用進口自列將永遠無法修復)
  4. 我不能使用列表框,因爲可以輸入任意數量的行數據,並且我需要在每一行中進行選擇
  5. 不能使用MS Access進行數據庫管理,因爲我的工具類型適用於輸入數據,大多數用戶不熟悉訪問(此外它不允許容易地複製粘貼數據)

是重新更好的方法?

回答

1

在這個答案,我提供了一個技術,是非常普遍的,當我開始工作作爲一個程序員45年但我還沒有看到任何人在普通的應用程序使用,但自己在許多年。我們從編譯器開發中借用了這種技術,但使用起來卻不那麼正式。

在完全成熟的技術,就不會有五個步驟:

  1. 設計中方便用於人的方式編碼該說明書的方法。
  2. 對規範進行編碼。
  3. 設計一個或多個表格以便於快速處理的方式保存規格。
  4. 設計並實現一個程序,將人類格式轉換爲快速處理格式。
  5. 設計並實現一個程序來解釋快速處理格式並執行所需的操作。

不被要求爲每一個問題的所有五個步驟;有時人類和快速處理的格式可能是相同的。這聽起來很複雜,但它使我們能夠輕鬆高效地解決許多複雜問題。

在下面的工作表中,我編碼了我對您所需驗證類型的理解。

|   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。

我沒有足夠的客戶要求的瞭解才知道這是不是最好的或你的驗證要求的完整表示。不過,如果你喜歡這種技術,我希望你能明白,並且可以爲你的需求提供方便的表達。

接下來我需要定義這個規範的快速處理形式。我設計了四個表並實現低於轉換的人工作表格式,以快速處理的格式,然後輸出這些表格準備立即窗口中的內容將被放置在這個答案代碼:

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,即沒有條件。允許的值是值表中的條目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 
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 

末次

+0

感謝您的解釋..我嘗試一下,我會回到你身邊 –

0

如果你要堅持命名範圍,你應該使用INDEX和COUNTA公式來使你的命名範圍動態化。這樣您可以將記錄添加到列表中,並且命名的範圍會自動調整。但接下來我會告訴你不要使用命名範圍。

這種鏈接的數據驗證對於簡單的鏈接列表很好。但是你的情況並不簡單,我認爲你需要遠離DV和ActiveX控件,可能在用戶窗體上。

您可以找到幾個複雜程度級別。一方面是你現在擁有的。另一方面,所有東西都存放在數據庫中,而Excel是適當的關係數據庫的計算引擎/前端。你可能會在這兩個中間結束。

我沒有足夠的信息給你一個真正相關的,詳細的答案,所以我會做出一堆假設,你必須認識到什麼時候它不適合你的情況。我認爲你需要創建一個用戶表單來處理數據錄入。用戶表單上的列表框/組合框將通過代碼動態更新。用戶表單將通過功能區,右鍵菜單或「編輯」超鏈接進行調用。用戶表單將填充當前選定的行。

然後,您將擁有複製和粘貼選項。用戶可以將單個項目複製並粘貼到用戶窗體中,並且您的代碼將驗證它們。或者他們可以複製代碼將驗證的整個信息記錄。

不要回避作爲後端的訪問。我的大部分項目都是由Excel控制的Jet數據庫。 Excel是計算引擎,輸入機制和報告機制。

+0

相信我,我不使用接入的唯一原因是因爲我的用戶不熟悉it..secondly我不能使用用戶表格的行進行數據添加行,因爲我的一個行都有大約需要填充20列,並且用戶希望能夠粘貼各個列......我嚴重地不想堅持命名的範圍,但是可以解釋如何使它們變得容易動態? –