您好Stackoverflow社区,
以下是Excel中“Sheet 1”的A列和B列的网站列表和客户列表。
Site Customer
Paddington A
Sydney B
Vaucluse A
Maroubra A
Woollahra B
Sydney A
Sydney A
我遇到的问题如下:
我的网站数据验证列表是唯一的(没有重复)。但是,我也需要我的客户在性质上也是独一无二的。问题示例:“悉尼”在站点列表中是唯一的,但选择“悉尼”时,客户列表中的客户为B,A,A。
以下是我的VBA代码:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Long, LastRow As Long, n As Long
Dim MyCol As Collection
Dim SearchString As String, TempList As String
Application.EnableEvents = False
On Error GoTo Whoa
'~~> Find LastRow in Col A
LastRow = Range("A" & Rows.Count).End(xlUp).Row
If Not Intersect(Target, Columns(1)) Is Nothing Then
Set MyCol = New Collection
'~~> Get the data from Col A into a collection
For i = 2 To LastRow
If Len(Trim(Range("A" & i).Value)) <> 0 Then
On Error Resume Next
MyCol.Add CStr(Range("A" & i).Value), CStr(Range("A" & i).Value)
On Error GoTo 0
End If
Next i
'~~> Create a list for the DV List
For n = 1 To MyCol.Count
TempList = TempList & "," & MyCol(n)
Next
TempList = Mid(TempList, 2)
Range("D1").ClearContents: Range("D1").Validation.Delete
'~~> Create the DV List
If Len(Trim(TempList)) <> 0 Then
With Range("D1").Validation
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=TempList
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
'~~> Capturing change in cell D1
ElseIf Not Intersect(Target, Range("D1")) Is Nothing Then
SearchString = Range("D1").Value
TempList = FindRange(Range("A2:A" & LastRow), SearchString)
Range("E1").ClearContents: Range("E1").Validation.Delete
If Len(Trim(TempList)) <> 0 Then
'~~> Create the DV List
With Range("E1").Validation
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=TempList
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End If
LetsContinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
'~~> Function required to find the list from Col B
Function FindRange(FirstRange As Range, StrSearch As String) As String
Dim aCell As Range, bCell As Range, oRange As Range
Dim ExitLoop As Boolean
Dim strTemp As String
Set aCell = FirstRange.Find(what:=StrSearch, LookIn:=xlValues, _
lookat:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not aCell Is Nothing Then
Set bCell = aCell
strTemp = strTemp & "," & aCell.Offset(, 1).Value
Do While ExitLoop = False
Set aCell = FirstRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
strTemp = strTemp & "," & aCell.Offset(, 1).Value
Else
ExitLoop = True
End If
Loop
FindRange = Mid(strTemp, 2)
End If
End Function
任何帮助都会受到赞赏
提前致谢
答案 0 :(得分:0)
如果您不关心丢失重复的行,那么如果您添加该行,您的程序将获得两者的所有唯一值:
Range("A:B").RemoveDuplicates Columns:=Array(1, 2), Header:=xlYes
在顶部 - 在On Error
之后和LastRow计算之前
On Error GoTo Whoa
'~~> Find LastRow in Col A
LastRow = Range("A" & Rows.Count).End(xlUp).Row
答案 1 :(得分:0)
通过跳过代码的某些部分,它应该按照您的意愿执行:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim vals As Variant, MyCol As New Collection, runner As Variant, str As String, i As Long
If Not Intersect(Target, Columns(1)) Is Nothing Then
vals = Range("A2", Cells(Rows.Count, 1).End(xlUp)).Value2
Range("D1").ClearContents
On Error Resume Next
For Each runner In vals
If Len(Trim(runner)) Then
MyCol.Add Trim(runner), Trim(runner)
End If
Next
On Error GoTo 0
If MyCol.Count Then
For Each runner In MyCol
str = str & "," & runner
Next
With Range("D1").Validation
.Delete
.Add 3, 1, 1, Mid(str, 2)
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
ElseIf Not Intersect(Target, Range("D1")) Is Nothing Then
vals = Range("B2", Cells(Rows.Count, 1).End(xlUp)).Value2
runner = Range("D1").Value2
Range("E1").ClearContents
On Error Resume Next
For i = 1 To UBound(vals)
If Trim(vals(i, 1)) = runner Then
MyCol.Add Trim(vals(i, 2)), Trim(vals(i, 2))
End If
Next
On Error GoTo 0
If MyCol.Count Then
For Each runner In MyCol
str = str & "," & runner
Next
With Range("E1").Validation
.Delete
.Add 3, 1, 1, Mid(str, 2)
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End If
End Sub
使用您提供的数据对其进行测试 - &gt;采取了预期的行为。
修改强>
对于同样的排序,我建议稍微重写一下sub以保持它小(虽然有些东西不会那么明显)
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim vals As Variant, runner As Variant
Dim MyCol As New Collection
Dim str As String, str2 As String
Dim i As Long
Dim tp As Boolean
If Not Intersect(Target, Union(Columns(1), Range("D1"))) Is Nothing Then
Application.EnableEvents = False
tp = Not Intersect(Target, Columns(1)) Is Nothing
vals = Range("B2", Cells(Rows.Count, 1).End(xlUp)).Value2
Range(Array("E1", "D1:E1")(-tp)).ClearContents
runner = IIf(tp, " ", Range("D1").Value2)
On Error Resume Next
For i = 1 To UBound(vals)
If (Trim(vals(i, 1)) = runner) Or (Len(Trim(vals(i, 1))) > 0 And tp) Then
MyCol.Add Trim(vals(i, 2 + tp)), Trim(vals(i, 2 + tp))
End If
Next
On Error GoTo 0
If MyCol.Count Then
While MyCol.Count
str2 = ""
For Each runner In MyCol
If Len(str2) Then
If StrComp(str2, runner) = 1 Then str2 = runner
Else
str2 = runner
End If
Next
str = str & "," & str2
MyCol.Remove str2
Wend
With Range(Array("E1", "D1")(-tp)).Validation
.Delete
.Add 3, 1, 1, Mid(str, 2)
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
Application.EnableEvents = True
End If
End Sub
如果您有任何疑问,请询问;)