使用范围名称的示例:
Dim ws As Worksheet, rng As Range, nm As Name
Set ws = ActiveSheet
Set rng = ws.Range("A2")
Names.Add Name:="testName", RefersTo:=rng
Set nm = Application.Names("testName")
ws.Rows(2).Delete 'Range has been deleted.
If InStr(1, nm.RefersTo, "#REF!") > 0 Then
'If InStr(1, Names("testName").RefersTo, "#REF!") > 0 Then
Debug.Print "lost reference"
Else
Debug.Print rng.Address()
End If
nm.Delete
'Names.Add Name:="testName", RefersTo:=""
以下是一个示例表模块,用于将Excel列表对象与数据库表(MS Access)同步。
更新于2020年7月5日:使用下面的代码进行一些测试似乎显示在多个单元格选择的情况下,“名称”编辑器窗口面板中所选行/列的计数器信息丢失。
Private IdAr As Variant, myCount As Integer
Private Sub Worksheet_Activate()
Names.Add Name:="myName", RefersTo:=Selection, Visible:=False
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Rows.Count = Me.Rows.Count Then Exit Sub
On Error GoTo ExceptionHandling
Names.Add Name:="myName", RefersTo:=Target, Visible:=False
If Not Application.Intersect(Target, Me.ListObjects("Table2").DataBodyRange) Is Nothing Then
Dim tblRow As Long, y As Integer, i As Integer
tblRow = Target.Row - Me.ListObjects("Table2").HeaderRowRange.Row
y = Target.Rows.Count
If y > 1 Then
ReDim IdAr(0 To y - 1)
For i = 0 To y - 1
IdAr(i) = Me.ListObjects("Table2").ListColumns("ID").DataBodyRange(tblRow + i)
Next i
Else
'If Application.CutCopyMode = False Then
IdAr = Me.ListObjects("Table2").ListColumns("ID").DataBodyRange(tblRow).Value
'End If
End If
End If
CleanUp:
On Error Resume Next
Exit Sub
ExceptionHandling:
MsgBox "Error: " & Err.Description
Resume CleanUp
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ExceptionHandling
Application.EnableEvents = False
If Not Application.Intersect(Target, Me.ListObjects("Table2").DataBodyRange) Is Nothing Then
Dim myCell As Range
For Each myCell In Target
If Not Application.Intersect(myCell, Me.ListObjects("Table2").ListColumns("ID").DataBodyRange) Is Nothing Then
If InStr(1, Names("myName").RefersTo, "#") > 0 Then
Debug.Print "Lost reference"
Delete_record
myCount = myCount + 1
Cancelado = True
Else
If myCell.Text = vbNullString Then
Debug.Print "Selecting listObject row and clear contents"
Delete_record
myCount = myCount + 1
Cancelado = True
End If
End If
Else
If Cancelado = False Then
If Not Application.Intersect(myCell, Me.Range("Table2[[FIELD1]:[FIELD3]]")) Is Nothing Then Update_record myCell
End If
End If
Next myCell
End If
CleanUp:
On Error Resume Next
myCount = 0
Application.EnableEvents = True
Exit Sub
ExceptionHandling:
MsgBox "Error: " & Err.Description
Resume CleanUp
End Sub
Sub Update_record(myCell As Range)
On Error GoTo ExceptionHandling
Dim tblRow As Long, IdTbl As Long, sField As String, sSQL As String
sField = Me.ListObjects("Table2").HeaderRowRange(myCell.Column)
tblRow = myCell.Row - Me.ListObjects("Table2").HeaderRowRange.Row
IdTbl = Me.ListObjects("Table2").ListColumns("ID").DataBodyRange(tblRow).Value
'Dim cnStr As String
'cnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sPath & ";Jet OLEDB:Database Password=123"
'Dim cn As ADODB.Connection
'Set cn = New ADODB.Connection
'cn.CursorLocation = adUseServer
'cn.Open cnStr
If IdTbl > 0 Then
sSQL = "UPDATE MYTABLE SET " & sField & " = '" & myCell.Value & "' WHERE ID = " & Me.ListObjects("Table2").ListColumns("ID").DataBodyRange(tblRow).Value
MsgBox sSQL
'Dim cmd As ADODB.Command
'Set cmd = New ADODB.Command
'Set cmd.ActiveConnection = cn
'cmd.CommandText = sSQL
'cmd.Execute , , adCmdText + adExecuteNoRecords
''cn.Execute sSQL, RecsAffected 'alternative to Command
''Debug.Print RecsAffected
Else
sSQL = "SELECT ID, " & sField & " FROM MYTABLE"
MsgBox sSQL
'Dim rst As ADODB.Recordset
'Set rst = New ADODB.Recordset
'rst.Open sSQL, cn, adOpenForwardOnly, adLockOptimistic, adCmdText
'cn.BeginTrans
'rst.AddNew
'rst(sField).Value = myCell.Value
'rst.Update
'IdTbl = rst(0).Value
'MsgBox "New Auto-increment value is: " & IdTbl
'tbl.ListColumns("ID").DataBodyRange(Fila) = IdTbl
'rst.Close
'cn.CommitTrans
End If
CleanUp:
On Error Resume Next
cn.Close
Exit Sub
ExceptionHandling:
MsgBox "Error: " & Err.Description & vbLf & Err.Number
Resume CleanUp
Resume 'for debugging
End Sub
Sub Delete_record()
Dim sSQL As String
If IsArray(IdAr) Then
sSQL = "DELETE FROM MYTABLE WHERE ID = " & IdAr(myCount)
MsgBox sSQL
Else
sSQL = "DELETE FROM MYTABLE WHERE ID = " & IdAr
MsgBox sSQL
End If
End Sub
更新于2020年8月2日,我最终使用以下代码检测已删除的行,并从Excel ListObject表向数据库表进行向上同步:
Private IdAr As Variant, tbRows As Integer, myCount As Integer, Cancelado As Boolean
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Rows.Count = Me.Rows.Count Then Exit Sub
On Error GoTo ExceptionHandling
If Not Application.Intersect(Target, Me.ListObjects("Table1").DataBodyRange) Is Nothing Then
Dim tblRow As Long, y As Integer, i As Integer
tblRow = Target.Row - Me.ListObjects("Table1").HeaderRowRange.Row
y = Target.Rows.Count
If y > 1 Then
ReDim IdAr(0 To y - 1)
For i = 0 To y - 1
IdAr(i) = Me.ListObjects("Table1").ListColumns("ID").DataBodyRange(tblRow + i)
Next i
Else
'If Application.CutCopyMode = False Then
IdAr = Me.ListObjects("Table1").ListColumns("ID").DataBodyRange(tblRow).Value
'End If
End If
tbRows = Me.ListObjects("Table1").ListRows.Count
End If
CleanUp:
On Error Resume Next
Exit Sub
ExceptionHandling:
MsgBox "Error: " & Err.Description
Resume CleanUp
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ExceptionHandling
Application.EnableEvents = False
If Not Application.Intersect(Target, Me.ListObjects("Table1").DataBodyRange) Is Nothing Then
Cancelado = False
Dim myCell As Range
For Each myCell In Target
If Not Application.Intersect(myCell, Me.ListObjects("Table1").ListColumns("ID").DataBodyRange) Is Nothing Then
If Me.ListObjects("Table1").ListRows.Count > tbRows Then
Cancelado = True
Else
If Me.ListObjects("Table1").ListRows.Count = tbRows Then
If myCell.Text = vbNullString Then
Debug.Print "Selected ListObject Row and Cleared Contents"
Cancelado = True
Delete_record
myCount = myCount + 1
End If
Else
Cancelado = True
Debug.Print "ListObject Row Deleted"
Delete_record
myCount = myCount + 1
End If
End If
Else
If Cancelado = False Then
If Not Application.Intersect(myCell, Me.Range("Table1[[FIELD1]:[FIELD3]]")) Is Nothing Then Update_record myCell
End If
End If
Next myCell
End If
CleanUp:
On Error Resume Next
myCount = 0
Application.EnableEvents = True
Exit Sub
ExceptionHandling:
MsgBox "Error: " & Err.Description & vbLf & Err.Number
Resume CleanUp
Resume 'for debugging
End Sub
Sub Update_record(myCell As Range)
On Error GoTo ExceptionHandling
Dim tblRow As Long, IdTbl As Long, sField As String, sSQL As String
sField = Me.ListObjects("Table1").HeaderRowRange(myCell.Column)
tblRow = myCell.Row - Me.ListObjects("Table1").HeaderRowRange.Row
IdTbl = Me.ListObjects("Table1").ListColumns("ID").DataBodyRange(tblRow).Value
'Dim cnStr As String
'cnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sPath & ";Jet OLEDB:Database Password=123"
'Dim cn As ADODB.Connection
'Set cn = New ADODB.Connection
'cn.CursorLocation = adUseServer
'cn.Open cnStr
If IdTbl > 0 Then
sSQL = "UPDATE MYTABLE SET " & sField & " = '" & myCell.Value & "' WHERE ID = " & Me.ListObjects("Table1").ListColumns("ID").DataBodyRange(tblRow).Value
MsgBox sSQL
'Dim cmd As ADODB.Command
'Set cmd = New ADODB.Command
'Set cmd.ActiveConnection = cn
'cmd.CommandText = sSQL
'cmd.Execute , , adCmdText + adExecuteNoRecords
''cn.Execute sSQL, RecsAffected 'alternative to Command
''Debug.Print RecsAffected
Else
sSQL = "SELECT ID, " & sField & " FROM MYTABLE"
MsgBox sSQL
'Dim rst As ADODB.Recordset
'Set rst = New ADODB.Recordset
'rst.Open sSQL, cn, adOpenForwardOnly, adLockOptimistic, adCmdText
'cn.BeginTrans
'rst.AddNew
'rst(sField).Value = myCell.Value
'rst.Update
'IdTbl = rst(0).Value
'MsgBox "New Auto-increment value is: " & IdTbl
'Me.ListObjects("Table1").ListColumns("ID").DataBodyRange(tblRow) = IdTbl
'rst.Close
'cn.CommitTrans
End If
CleanUp:
On Error Resume Next
If Not cn Is Nothing Then
If cn.State = adStateOpen Then cn.Close
End If
'DriveMapDel
'https://codereview.stackexchange.com/questions/143895/making-repeated-adodb-queries-from-excel-sql-server
'... get rid of the redundant assignments to Nothing; the objects are going out of scope at End Sub, they're being destroyed anyway.
'Set rst = Nothing
'Set cmd = Nothing
'Set cn = Nothing
Exit Sub
ExceptionHandling:
MsgBox "Error: " & Err.Description & vbLf & Err.Number
Resume CleanUp
Resume 'for debugging
End Sub
Sub Delete_record()
Dim sSQL As String
If IsArray(IdAr) Then
sSQL = "DELETE FROM MYTABLE WHERE ID = " & IdAr(myCount)
MsgBox sSQL
Else
sSQL = "DELETE FROM MYTABLE WHERE ID = " & IdAr
MsgBox sSQL
End If
End Sub
Sum()
公式,并且被重定向到具有Avg()
的单元格,则该工作表将出现问题。 - spinjector#REF!
错误的原因吗? - Mathieu Guindon