Access Deleting Duplicates with query - ms-access

I'm trying to make a query that will delete all the duplicate rows from an Access 2010 table. And my problem is that the query is deleting all the duplicate records (even original).
So let's say I have 1 record that is original and 2 records that are duplicates. Instead of deleting 2 duplicates, it deletes all 3.
Here is what I did:
DELETE *
FROM Table
WHERE [field1] IN (SELECT [field1] FROM [table] As Tmp
GROUP BY [field1],[field2],[field3],[field4],[field5] HAVING Count(*)>1);
And Primary Key field is (ID)

Access will never allow you to DELETE in a GROUP BY query. So you need a fundamentally different approach.
Create a query which returns only one row for each of the duplicated field groups:
SELECT [field1], [field2], [field3], [field4], [field5], Min([ID]) AS keep_id
FROM [table]
GROUP BY [field1], [field2], [field3], [field4], [field5];
Save that as qryKeepIDs, and then use it a DELETE query:
DELETE FROM [Table]
WHERE [Table].ID Not In (SELECT keep_id FROM qryKeepIDs);

Following Code will generate queries which work same as #HansUp mentioned. This should give an advantage if you like to check a lot of different tables for duplicates. Besides deleting "all" you even have the chance to delete a selection of duplicates.
Would be great to give some ideas for improvement:
Public Sub CleanUpDuplicates(strTable As String, strQuery, strID As String, strField1 As String, _
Optional strField2 As String, _
Optional strField3 As String, _
Optional strField4 As String, _
Optional strField5 As String)
strQueryDUP = strQuery & "_DUP"
strQueryCleanUp_Single = strQuery & "_CleanUp_Single"
strQueryCleanUp_All = strQuery & "_CleanUp_All"
'SELECT [field1], [field2], [field3], [field4], [field5], Min([ID]) AS keyID
strSQLDUP = "SELECT [" & strField1
If strField2 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField2
If strField3 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField3
If strField4 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField4
If strField5 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField5
strSQLDUP = strSQLDUP & "], Min(" & strID & ") AS keyID "
'FROM [Table]
strSQLDUP = strSQLDUP & "FROM " & strTable & " "
'GROUP BY [field1], [field2], [field3], [field4], [field5];
strSQLDUP = strSQLDUP & "GROUP BY [" & strField1
If strField2 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField2
If strField3 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField3
If strField4 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField4
If strField5 <> "" Then strSQLDUP = strSQLDUP + "], [" & strField5
strSQLDUP = strSQLDUP & "];"
'FROM [Table]
strSQLCleanUp = "FROM " & strTable & " "
'WHERE [Table].ID Not In (SELECT keep_id FROM [Query]);
strSQLCleanUp = strSQLCleanUp & "WHERE " & strTable & "." & strID & " Not In (SELECT keyID FROM "
strSQLCleanUp = strSQLCleanUp & strQueryDUP & ");"
'SELECT [Table].*
strSQLCleanUp_Single = "SELECT " & strTable & ".* " & strSQLCleanUp
'DELETE [Table].*
strSQLCleanUp_All = "DELETE " & strTable & ".* " & strSQLCleanUp
'###### Create Queries ##########
Dim db As DAO.Database
Set db = CurrentDb
Dim qdfDUP As DAO.QueryDef
Dim qdfCleanUp_Single As DAO.QueryDef
Dim qdfCleanUp_All As DAO.QueryDef
On Error Resume Next
DoCmd.DeleteObject acQuery, strQueryDUP
Set qdfDUP = db.CreateQueryDef(strQueryDUP, strSQLDUP)
DoCmd.DeleteObject acQuery, strQueryCleanUp_Single
Set qdfCleanUp_Single = db.CreateQueryDef(strQueryCleanUp_Single, strSQLCleanUp_Single)
DoCmd.DeleteObject acQuery, strQueryCleanUp_All
Set qdfCleanUp_All = db.CreateQueryDef(strQueryCleanUp_All, strSQLCleanUp_All)
On Error GoTo 0
DoCmd.OpenQuery strQueryCleanUp_Single, acViewNormal
response = MsgBox("Do you like to clean-up all duplicates?", vbOKCancel + vbCritical, "Attention")
If response = vbOK Then
DoCmd.Close acQuery, strQueryCleanUp_Single
DoCmd.OpenQuery strQueryCleanUp_All, acViewNormal
End If
End Sub

We can use this query to delete duplicates and retain the unique one, Ex. 3 duplcates found and it retains 1 and deletes other 2.
Delete * From myTable Where UniqueID Not IN (select UniqueID From myTable Where UniqueID IN (select Min(UniqueID) From myTable Group by [Duplicates]))
Thank you.

Related

MS Access Query ColumnHidden Property

I've written some VBA code that (a) sets the SQL of a query based on input variables, (b) opens the query in datasheet view, and (c) hides or shows columns based on "true" / "false" values of check boxes in another table. This is considering the "ColumnHidden" property as described in Microsoft Dev Center help. Dev Center Help - ColumnHidden Property
When executing the code, (a) and (b) are working as intended. However, I get error 3270, "Property not found" at line fld.Properties("ColumnHidden") = False when executing (c). I've been unable to resolve the issue, even when trying the error handling method described in the Dev Center. Please help!
Dim rsLabel As DAO.Recordset, rsCOlumn As DAO.Recordset
Dim qryCPQ As DAO.QueryDef
Dim strLabel As String, strSQL As String, strColumn As String
Dim fld As DAO.Field
Dim dbs As DAO.Database
Dim prp As DAO.Property
Dim AttArray As Variant
Dim x As Integer
ReDim AttArray(19, 1)
For x = 1 To 20
AttArray(x - 1, 1) = "Att" & x
Next x
strLabel = "SELECT * FROM PM_qryLabels2 WHERE CAT_ID=" & Forms!CM_frmCollectionReportPre!cboFamily
Set rsLabel = CurrentDb.OpenRecordset(strLabel, dbOpenSnapshot)
rsLabel.MoveFirst
For x = 1 To 20
If Not IsNull(rsLabel.Fields("Att" & x)) Then
AttArray(x - 1, 1) = rsLabel.Fields("Att" & x)
Else
AttArray(x - 1, 1) = "Att" & x
End If
Next x
With CurrentDb
Set qryCPQ = .QueryDefs("CM_qryCollectionReport")
strSQL = "SELECT CM_qryCollectionEdit2.CATEGORY, CM_qryCollectionEdit2.Part_No, CM_qryCollectionEdit2.CPQ_Material, CM_qryCollectionEdit2.CPQ_LaborMach, CM_qryCollectionEdit2.CPQ_LaborAssy, CM_qryCollectionEdit2.CPQ_LaborPipe, CM_qryCollectionEdit2.CPQ_LaborTest, CM_qryCollectionEdit2.CPQ_LaborPack, CM_qryCollectionEdit2.CPQ_LaborShip, CM_qryCollectionEdit2.CPQ_Sub, " & _
"PM_qryOptions.Att1 As [" & AttArray(0, 1) & "], PM_qryOptions.Att2 As [" & AttArray(1, 1) & "], PM_qryOptions.Att3 As [" & AttArray(2, 1) & "], PM_qryOptions.Att4 As [" & AttArray(3, 1) & "], PM_qryOptions.Att5 As [" & AttArray(4, 1) & "], PM_qryOptions.Att6 As [" & AttArray(5, 1) & "], PM_qryOptions.Att7 As [" & AttArray(6, 1) & "], PM_qryOptions.Att8 As [" & AttArray(7, 1) & "], PM_qryOptions.Att9 As [" & AttArray(8, 1) & "], PM_qryOptions.Att10 As [" & AttArray(9, 1) & "], PM_qryOptions.Att11 As [" & AttArray(10, 1) & "], PM_qryOptions.Att12 As [" & AttArray(11, 1) & "], PM_qryOptions.Att13 As [" & AttArray(12, 1) & "], PM_qryOptions.Att14 As [" & AttArray(13, 1) & "], PM_qryOptions.Att15 As [" & AttArray(14, 1) & "], PM_qryOptions.Att16 As [" & AttArray(15, 1) & "], PM_qryOptions.Att17 As [" & AttArray(16, 1) & "], PM_qryOptions.Att18 As [" & AttArray(17, 1) & "], PM_qryOptions.Att19 As [" & AttArray(18, 1) & "], PM_qryOptions.Att20 As [" & AttArray(19, 1) & "] " & _
"FROM CM_qryCollectionEdit2 INNER JOIN PM_qryOptions ON CM_qryCollectionEdit2.Part_No = PM_qryOptions.Part_No " & _
"WHERE ((CM_qryCollectionEdit2.CAT_ID)=" & Me.cboFamily & " AND ((CM_qryCollectionEdit2.CPQ_Publish)=True));"
qryCPQ.SQL = strSQL
qryCPQ.Close
Set qryCPQ = Nothing
End With
DoCmd.OpenQuery "CM_qryCollectionReport", , acReadOnly
Set dbs = CurrentDb
For x = 1 To 20
Set fld = dbs.QueryDefs!CM_qryCollectionReport.Fields(AttArray(x - 1, 1))
fld.Properties("ColumnHidden") = False
strColumn = "SELECT * FROM PM_Attributes WHERE CAT_ID=" & Forms!CM_frmCollectionReportPre!cboFamily & " AND [ATTRIBUTE]='" & AttArray(x - 1, 1) & "'"
Set rsCOlumn = CurrentDb.OpenRecordset(strColumn, dbOpenSnapshot)
If Not rsCOlumn.EOF Then
If rsCOlumn![CPQ_Publish] = False Then
fld.Properties("ColumnHidden") = True
End If
End If
rsCOlumn.Close
Set rsCOlumn = Nothing
Set fld = Nothing
Next x
Set dbs = Nothing
DoCmd.Close acForm, "CM_frmCollectionReportPre", acSaveNo
Per Eric Von Asmuth's suggestion, I've added in the error handling, so the code now appears as follows. Yet I still receive error 3270 at the same location. Hasn't fixed a thing.
Dim rsLabel As DAO.Recordset, rsCOlumn As DAO.Recordset
Dim qryCPQ As DAO.QueryDef
Dim strLabel As String, strSQL As String, strColumn As String
Dim fld As DAO.Field
Dim dbs As DAO.Database
Dim prp As DAO.Property
Dim AttArray As Variant
Dim x As Integer
Const conErrPropertyNotFound = 3270
' Turn off error trapping
On Error Resume Next
ReDim AttArray(19, 1)
For x = 1 To 20
AttArray(x - 1, 1) = "Att" & x
Next x
strLabel = "SELECT * FROM PM_qryLabels2 WHERE CAT_ID=" & Forms!CM_frmCollectionReportPre!cboFamily
Set rsLabel = CurrentDb.OpenRecordset(strLabel, dbOpenSnapshot)
rsLabel.MoveFirst
For x = 1 To 20
If Not IsNull(rsLabel.Fields("Att" & x)) Then
AttArray(x - 1, 1) = rsLabel.Fields("Att" & x)
Else
AttArray(x - 1, 1) = "Att" & x
End If
Next x
'AFTER FORM IS OPEN, NEED TO HIDE COLUMNS BASEDON CPQ_PUBLISH
With CurrentDb
Set qryCPQ = .QueryDefs("CM_qryCollectionReport")
strSQL = "SELECT CM_qryCollectionEdit2.CATEGORY, CM_qryCollectionEdit2.Part_No, CM_qryCollectionEdit2.CPQ_Material, CM_qryCollectionEdit2.CPQ_LaborMach, CM_qryCollectionEdit2.CPQ_LaborAssy, CM_qryCollectionEdit2.CPQ_LaborPipe, CM_qryCollectionEdit2.CPQ_LaborTest, CM_qryCollectionEdit2.CPQ_LaborPack, CM_qryCollectionEdit2.CPQ_LaborShip, CM_qryCollectionEdit2.CPQ_Sub, " & _
"PM_qryOptions.Att1 As [" & AttArray(0, 1) & "], PM_qryOptions.Att2 As [" & AttArray(1, 1) & "], PM_qryOptions.Att3 As [" & AttArray(2, 1) & "], PM_qryOptions.Att4 As [" & AttArray(3, 1) & "], PM_qryOptions.Att5 As [" & AttArray(4, 1) & "], PM_qryOptions.Att6 As [" & AttArray(5, 1) & "], PM_qryOptions.Att7 As [" & AttArray(6, 1) & "], PM_qryOptions.Att8 As [" & AttArray(7, 1) & "], PM_qryOptions.Att9 As [" & AttArray(8, 1) & "], PM_qryOptions.Att10 As [" & AttArray(9, 1) & "], PM_qryOptions.Att11 As [" & AttArray(10, 1) & "], PM_qryOptions.Att12 As [" & AttArray(11, 1) & "], PM_qryOptions.Att13 As [" & AttArray(12, 1) & "], PM_qryOptions.Att14 As [" & AttArray(13, 1) & "], PM_qryOptions.Att15 As [" & AttArray(14, 1) & "], PM_qryOptions.Att16 As [" & AttArray(15, 1) & "], PM_qryOptions.Att17 As [" & AttArray(16, 1) & "], PM_qryOptions.Att18 As [" & AttArray(17, 1) & "], PM_qryOptions.Att19 As [" & AttArray(18, 1) & "], PM_qryOptions.Att20 As [" & AttArray(19, 1) & "] " & _
"FROM CM_qryCollectionEdit2 INNER JOIN PM_qryOptions ON CM_qryCollectionEdit2.Part_No = PM_qryOptions.Part_No " & _
"WHERE ((CM_qryCollectionEdit2.CAT_ID)=" & Me.cboFamily & " AND ((CM_qryCollectionEdit2.CPQ_Publish)=True));"
qryCPQ.SQL = strSQL
qryCPQ.Close
'Set qryCPQ = Nothing
End With
DoCmd.OpenQuery "CM_qryCollectionReport", , acReadOnly
Set dbs = CurrentDb
For x = 1 To 20
Set fld = dbs.QueryDefs!CM_qryCollectionReport.Fields(AttArray(x - 1, 1))
fld.Properties("ColumnHidden") = False
' Error may have occurred when value was set.
' Display error message or create property when property didn't exist
If Err.Number <> 0 Then
If Err.Number <> conErrPropertyNotFound Then
On Error GoTo 0
MsgBox "Couldn't set property 'ColumnHidden' " & _
"on field '" & fld.Name & "'", vbCritical
Else
On Error GoTo 0
Set prp = fld.CreateProperty("ColumnHidden", dbLong, False)
fld.Properties.Append prp
End If
End If
strColumn = "SELECT * FROM PM_Attributes WHERE CAT_ID=" & Forms!CM_frmCollectionReportPre!cboFamily & " AND [ATTRIBUTE]='" & AttArray(x - 1, 1) & "'"
Set rsCOlumn = CurrentDb.OpenRecordset(strColumn, dbOpenSnapshot)
If Not rsCOlumn.EOF Then
If rsCOlumn![CPQ_Publish] = False Then
fld.Properties("ColumnHidden") = True
End If
End If
rsCOlumn.Close
Set rsCOlumn = Nothing
Set fld = Nothing
Set prp = Nothing
Next x
Set dbs = Nothing
DoCmd.Close acForm, "CM_frmCollectionReportPre", acSaveNo
Screen shots of error:
If you closely look at the example code in the article you referred to, it includes error capturing, and creating the property if it didn't exist. This is because the property may or may not exist based on unpredictable circumstances.
Adapted from the Linked article:
Const conErrPropertyNotFound = 3270
' Turn off error trapping.
On Error Resume Next
'Set the field to false here
fld.Properties("ColumnHidden") = False
' Error may have occurred when value was set.
' Display error message or create property when property didn't exist
If Err.Number <> 0 Then
If Err.Number <> conErrPropertyNotFound Then
On Error GoTo 0
MsgBox "Couldn't set property 'ColumnHidden' " & _
"on field '" & fld.Name & "'", vbCritical
Else
On Error GoTo 0
Set prp = fld.CreateProperty("ColumnHidden", dbLong, False)
fld.Properties.Append prp
End If
End If
Since you've already set the field to False, you don't need to error trap in case the field doesn't exist when setting it back to True
You can also choose to check if the property does exist by iterating through all properties, which is best done in a separate function. This avoids error trapping, but may take longer to run

Change Navigation pane group in access through vba

I have a module of VBA code in access that creates 4 new tables and adds them to the database. I would like to add in a part at the end where they are organized in the navigation pane through custom groups so that way they are all organized. Would this be possible through vba?
EDIT:
I don't want the tables to be in the unassigned objects group. I want to change the name of that group through VBA.
EDIT: Added more code to add other object types to the custom Nav group.
The following code will assign tables to your custom Navigation Group.
WARNING!! There is a 'refresh' issue of table 'MSysNavPaneObjectIDs' that I am still trying to resolve. If you create a new table and then try to add to your group - sometimes it works on the first try, other times it fails but will work after a delay (sometimes up to five or ten minutes!)
At this moment, I got around the issue (when it fails) by reading info from table 'MSysObjects', then adding a new record to 'MSysNavPaneObjectIDs'.
The code below simply creates five small tables and adds to Nav Group 'Clients'
Modify the code to use your Group name / table names.
Option Compare Database
Option Explicit
Sub Test_My_Code()
Dim dbs As DAO.Database
Dim strResult As String
Dim i As Integer
Dim strSQL As String
Dim strTableName As String
Set dbs = CurrentDb
For i = 1 To 5
strTableName = "Query" & i
'>>> CHANGE FOLLOWING LINE TO YOUR CUSTOM NAME
' Pass the Nav Group, Object Name, Object Type
strResult = SetNavGroup("Clients", strTableName, "Query")
Debug.Print strResult
Next i
For i = 1 To 5
strTableName = "0000" & i
strSQL = "CREATE TABLE " & strTableName & " (PayEmpID INT, PayDate Date);"
dbs.Execute strSQL
'>>> CHANGE FOLLOWING LINE TO YOUR CUSTOM NAME
' Pass the Nav Group, Object Name, Object Type
strResult = SetNavGroup("Clients", strTableName, "Table")
Debug.Print strResult
Next i
dbs.Close
Set dbs = Nothing
End Sub
Function SetNavGroup(strGroup As String, strTable As String, strType As String) As String
Dim strSQL As String
Dim dbs As DAO.Database
Dim rs As DAO.recordSet
Dim lCatID As Long
Dim lGrpID As Long
Dim lObjID As Long
Dim lType As Long
SetNavGroup = "Failed"
Set dbs = CurrentDb
' Ignore the following code unless you want to manage 'Categories'
' Table MSysNavPaneGroupCategories has fields: Filter, Flags, Id (AutoNumber), Name, Position, SelectedObjectID, Type
' strSQL = "SELECT Id, Name, Position, Type " & _
' "FROM MSysNavPaneGroupCategories " & _
' "WHERE (((MSysNavPaneGroupCategories.Name)='" & strGroup & "'));"
' Set rs = dbs.OpenRecordset(strSQL)
' If rs.EOF Then
' MsgBox "No group named '" & strGroup & "' found. Will quit now.", vbOKOnly, "No Group Found"
' rs.Close
' Set rs = Nothing
' dbs.Close
' Set dbs = Nothing
' Exit Function
' End If
' lCatID = rs!ID
' rs.Close
' When you create a new table, it's name is added to table 'MSysNavPaneObjectIDs'
' Types
' Type TypeDesc
'-32768 Form
'-32766 Macro
'-32764 Reports
'-32761 Module
'-32758 Users
'-32757 Database Document
'-32756 Data Access Pages
'1 Table - Local Access Tables
'2 Access object - Database
'3 Access object - Containers
'4 Table - Linked ODBC Tables
'5 Queries
'6 Table - Linked Access Tables
'8 SubDataSheets
If LCase(strType) = "table" Then
lType = 1
ElseIf LCase(strType) = "query" Then
lType = 5
ElseIf LCase(strType) = "form" Then
lType = -32768
ElseIf LCase(strType) = "report" Then
lType = -32764
ElseIf LCase(strType) = "module" Then
lType = -32761
ElseIf LCase(strType) = "macro" Then
lType = -32766
Else
MsgBox "Add your own code to handle the object type of '" & strType & "'", vbOKOnly, "Add Code"
dbs.Close
Set dbs = Nothing
Exit Function
End If
' Table MSysNavPaneGroups has fields: Flags, GroupCategoryID, Id, Name, Object, Type, Group, ObjectID, Position
Debug.Print "---------------------------------------"
Debug.Print "Add '" & strType & "' " & strTable & "' to Group '" & strGroup & "'"
strSQL = "SELECT GroupCategoryID, Id, Name " & _
"FROM MSysNavPaneGroups " & _
"WHERE (((MSysNavPaneGroups.Name)='" & strGroup & "') AND ((MSysNavPaneGroups.Name) Not Like 'Unassigned*'));"
Set rs = dbs.OpenRecordset(strSQL)
If rs.EOF Then
MsgBox "No group named '" & strGroup & "' found. Will quit now.", vbOKOnly, "No Group Found"
rs.Close
Set rs = Nothing
dbs.Close
Set dbs = Nothing
Exit Function
End If
Debug.Print rs!GroupCategoryID & vbTab & rs!ID & vbTab & rs!Name
lGrpID = rs!ID
rs.Close
Try_Again:
' Filter By Type
strSQL = "SELECT Id, Name, Type " & _
"FROM MSysNavPaneObjectIDs " & _
"WHERE (((MSysNavPaneObjectIDs.Name)='" & strTable & "') AND ((MSysNavPaneObjectIDs.Type)=" & lType & "));"
Set rs = dbs.OpenRecordset(strSQL)
If rs.EOF Then
' Seems to be a refresh issue / delay! I have found no way to force a refresh.
' This table gets rebuilt at the whim of Access, so let's try a different approach....
' Lets add the record vis code.
Debug.Print "Table not found in MSysNavPaneObjectIDs, try MSysObjects."
strSQL = "SELECT * " & _
"FROM MSysObjects " & _
"WHERE (((MSysObjects.Name)='" & strTable & "') AND ((MSysObjects.Type)=" & lType & "));"
Set rs = dbs.OpenRecordset(strSQL)
If rs.EOF Then
MsgBox "This is crazy! Table '" & strTable & "' not found in MSysObjects.", vbOKOnly, "No Table Found"
rs.Close
Set rs = Nothing
dbs.Close
Set dbs = Nothing
Exit Function
Else
Debug.Print "Table not found in MSysNavPaneObjectIDs, but was found in MSysObjects. Lets try to add via code."
strSQL = "INSERT INTO MSysNavPaneObjectIDs ( ID, Name, Type ) VALUES ( " & rs!ID & ", '" & strTable & "', " & lType & ")"
dbs.Execute strSQL
GoTo Try_Again
End If
End If
Debug.Print rs!ID & vbTab & rs!Name & vbTab & rs!type
lObjID = rs!ID
rs.Close
' Add the table to the Custom group
strSQL = "INSERT INTO MSysNavPaneGroupToObjects ( GroupID, ObjectID, Name ) VALUES ( " & lGrpID & ", " & lObjID & ", '" & strTable & "' )"
dbs.Execute strSQL
dbs.Close
Set dbs = Nothing
SetNavGroup = "Passed"
End Function
Thanks a lot for your code,
I had to modify it a little on my specific case due to the issue on the refresh of the table.
In fact I am recreating a table (deleting the old one before). As the MSysNavPaneObjectIDs does not refresh, the old ID is kept inside.
e.g. let's use a table tmpFoo that I want to put in a group TEMP.
tmpFoo is already in group TEMP. TEMP has ID 1 and tmpFoo has ID 1000
Then I delete tmpFoo, and immediately recreate tmpFoo.
tmpFoo is now in 'Unassigned Objects'.
In MSysObjects, ID of tmpFoo is now 1100, but in MSysNavPaneObjectIDs the table is not refreshed and the ID of tmpFoo here is still 1000.
In this case, in the table MSysNavPaneGroupToObjects a link between TEMP(1) and tmpFoo(1000) is created => Nothing happen as ID 1000 does not exists anymore in MSysObjects.
So, the modified code below get in all cases ID from MSysObjects, then check if the ID exists in MSysNavPaneObjectIDs.
If not, add the line, then use the same ID to add it to MSysNavPaneGroupToObjects.
In this way seems I do not have any refresh issue (adding Application.RefreshDatabaseWindow in the upper function).
Thanks again Wayne,
Function SetNavGroup(strGroup As String, strTable As String, strType As String) As String
Dim strSQL As String
Dim dbs As DAO.Database
Dim rs As DAO.Recordset
Dim lCatID As Long
Dim lGrpID As Long
Dim lObjID As Long
Dim lType As Long
SetNavGroup = "Failed"
Set dbs = CurrentDb
' When you create a new table, it's name is added to table 'MSysNavPaneObjectIDs'
' Types
' Type TypeDesc
'-32768 Form
'-32766 Macro
'-32764 Reports
'-32761 Module
'-32758 Users
'-32757 Database Document
'-32756 Data Access Pages
'1 Table - Local Access Tables
'2 Access object - Database
'3 Access object - Containers
'4 Table - Linked ODBC Tables
'5 Queries
'6 Table - Linked Access Tables
'8 SubDataSheets
If LCase(strType) = "table" Then
lType = 1
ElseIf LCase(strType) = "query" Then
lType = 5
ElseIf LCase(strType) = "form" Then
lType = -32768
ElseIf LCase(strType) = "report" Then
lType = -32764
ElseIf LCase(strType) = "module" Then
lType = -32761
ElseIf LCase(strType) = "macro" Then
lType = -32766
Else
MsgBox "Add your own code to handle the object type of '" & strType & "'", vbOKOnly, "Add Code"
dbs.Close
Set dbs = Nothing
Exit Function
End If
' Table MSysNavPaneGroups has fields: Flags, GroupCategoryID, Id, Name, Object, Type, Group, ObjectID, Position
Debug.Print "---------------------------------------"
Debug.Print "Add '" & strType & "' '" & strTable & "' to Group '" & strGroup & "'"
strSQL = "SELECT GroupCategoryID, Id, Name " & _
"FROM MSysNavPaneGroups " & _
"WHERE (((MSysNavPaneGroups.Name)='" & strGroup & "') AND ((MSysNavPaneGroups.Name) Not Like 'Unassigned*'));"
Set rs = dbs.OpenRecordset(strSQL)
If rs.EOF Then
MsgBox "No group named '" & strGroup & "' found. Will quit now.", vbOKOnly, "No Group Found"
rs.Close
Set rs = Nothing
dbs.Close
Set dbs = Nothing
Exit Function
End If
Debug.Print rs!GroupCategoryID & vbTab & rs!ID & vbTab & rs!Name
lGrpID = rs!ID
rs.Close
' Get Table ID From MSysObjects
strSQL = "SELECT * " & _
"FROM MSysObjects " & _
"WHERE (((MSysObjects.Name)='" & strTable & "') AND ((MSysObjects.Type)=" & lType & "));"
Set rs = dbs.OpenRecordset(strSQL)
If rs.EOF Then
MsgBox "This is crazy! Table '" & strTable & "' not found in MSysObjects.", vbOKOnly, "No Table Found"
rs.Close
Set rs = Nothing
dbs.Close
Set dbs = Nothing
Exit Function
End If
lObjID = rs!ID
Debug.Print "Table found in MSysObjects " & lObjID & " . Lets compare to MSysNavPaneObjectIDs."
' Filter By Type
strSQL = "SELECT Id, Name, Type " & _
"FROM MSysNavPaneObjectIDs " & _
"WHERE (((MSysNavPaneObjectIDs.ID)=" & lObjID & ") AND ((MSysNavPaneObjectIDs.Type)=" & lType & "));"
Set rs = dbs.OpenRecordset(strSQL)
If rs.EOF Then
' Seems to be a refresh issue / delay! I have found no way to force a refresh.
' This table gets rebuilt at the whim of Access, so let's try a different approach....
' Lets add the record via this code.
Debug.Print "Table not found in MSysNavPaneObjectIDs, add it from MSysObjects."
strSQL = "INSERT INTO MSysNavPaneObjectIDs ( ID, Name, Type ) VALUES ( " & lObjID & ", '" & strTable & "', " & lType & ")"
dbs.Execute strSQL
End If
Debug.Print lObjID & vbTab & strTable & vbTab & lType
rs.Close
' Add the table to the Custom group
strSQL = "INSERT INTO MSysNavPaneGroupToObjects ( GroupID, ObjectID, Name ) VALUES ( " & lGrpID & ", " & lObjID & ", '" & strTable & "' )"
dbs.Execute strSQL
dbs.Close
Set dbs = Nothing
SetNavGroup = "Passed"
End Function
Here's my code it's not as user-error friendly as the main code, but it should be a bit quicker to make a mass move.
Public Sub Test_My_Code()
Dim i As Long, db As Database, qd As QueryDef
Set db = CurrentDb
For i = 1 To 10
DoCmd.RunSQL "CREATE TABLE [~~Table:" & Format(i, "00000") & "](PayEmpID INT, PayDate Date)"
Set qd = db.CreateQueryDef("~~Query:" & Format(i, "00000"), "SELECT * FROM [~~Table:" & Format(i, "00000") & "];")
Next i
MsgBox IIf(SetNavGroup(CategorySelection:="Like '*'", GroupSelection:="='TestGroup'", ObjectSelection:="Like '~~Table:#####'"), "New Tables Moved", "Table Move Failed")
MsgBox IIf(SetNavGroup(CategorySelection:="Like '*'", GroupSelection:="='TestGroup'", ObjectSelection:="Like '~~Query:#####'"), "New Queries Moved", "Query Move Failed")
End Sub
Private Sub SetNavGroup_tst(): MsgBox IIf(SetNavGroup(GroupSelection:="='Verified Formularies'", ObjectSelection:="Like '*Verified*'"), "Tables Moved OK", "Failed"): End Sub
'Parameters:
' CategorySelection -- used to filter which custom(type=4) categories to modify
' ex select the 'Custom' Navigation Category (default): "='Custom'"
' GroupSelection -- used to filter which custom(type=-1) groups to add the objects to
' ex select a specific group: "='Verified Formularies'"
' ex select set of specific groups: "In ('Group Name1','Group Name2')"
' ObjectSelection -- used to filter which database objects to move under the groups
' ex select a range of tables: "Like '*Verified*'"
' UnassignedOnly -- used to only look at objects from the Unassigned group
' True - set only unassigned objects
' False - add objects even if they're already in a group
Public Function SetNavGroup(GroupSelection As String, ObjectSelection As String, Optional CategorySelection As String = "='Custom'", Optional UnassignedOnly As Boolean = True) As Boolean
SetNavGroup = False
If Trim(GroupSelection) = "" Then Exit Function
If Trim(ObjectSelection) = "" Then Exit Function
DoCmd.SetWarnings False
On Error GoTo SilentlyContinue
'TempTable Name
Dim ToMove As String
Randomize: ToMove = "~~ToMove_TMP" & (Fix(100000 * Rnd) Mod 100)
'Build temporary table of what to move
Dim SQL As String: SQL = _
"SELECT [Ghost:ToMove].* INTO [" & ToMove & "] " & _
"FROM ( " & _
"SELECT MSysNavPaneGroups.GroupCategoryID, MSysNavPaneGroupCategories.Name AS CategoryName, MSysNavPaneGroups.Id AS GroupID, MSysNavPaneGroups.Name AS GroupName, MSysObjects.Id AS ObjectID, MSysObjects.Name AS ObjectName, MSysObjects.Type AS ObjectType, '' AS ObjectAlias " & _
"FROM MSysObjects, MSysNavPaneGroupCategories INNER JOIN MSysNavPaneGroups ON MSysNavPaneGroupCategories.Id = MSysNavPaneGroups.GroupCategoryID " & _
"WHERE (((MSysNavPaneGroupCategories.Name) " & CategorySelection & ") AND ((MSysNavPaneGroups.Name) " & GroupSelection & ") AND MSysObjects.Name " & ObjectSelection & " AND ((MSysNavPaneGroupCategories.Type)=4) AND ((MSysNavPaneGroups.[Object Type Group])=-1)) " & _
"GROUP BY MSysNavPaneGroups.GroupCategoryID, MSysNavPaneGroupCategories.Name, MSysNavPaneGroups.Id, MSysNavPaneGroups.Name, MSysObjects.Id, MSysObjects.Name, MSysObjects.Type " & _
"ORDER BY Min(MSysNavPaneGroupCategories.Position), Min(MSysNavPaneGroups.Position)" & _
") AS [Ghost:ToMove] LEFT JOIN ( " & _
"SELECT MSysNavPaneGroups.GroupCategoryID, MSysNavPaneGroupToObjects.GroupID, MSysNavPaneGroupToObjects.ObjectID " & _
"FROM MSysNavPaneGroups INNER JOIN MSysNavPaneGroupToObjects ON MSysNavPaneGroups.Id = MSysNavPaneGroupToObjects.GroupID " & _
") AS [Ghost:AssignedObjects] ON ([Ghost:ToMove].ObjectID = [Ghost:AssignedObjects].ObjectID) AND ([Ghost:ToMove].GroupID = [Ghost:AssignedObjects].GroupID) AND ([Ghost:ToMove].GroupCategoryID = [Ghost:AssignedObjects].GroupCategoryID) " & _
"WHERE [Ghost:AssignedObjects].GroupCategoryID Is Null;"
If Not UnassignedOnly Then SQL = _
"SELECT MSysNavPaneGroups.GroupCategoryID, MSysNavPaneGroupCategories.Name AS CategoryName, MSysNavPaneGroups.Id AS GroupID, MSysNavPaneGroups.Name AS GroupName, MSysObjects.Id AS ObjectID, MSysObjects.Name AS ObjectName, MSysObjects.Type AS ObjectType, '' AS ObjectAlias " & _
"INTO [" & ToMove & "] " & _
"FROM MSysObjects, MSysNavPaneGroupCategories INNER JOIN MSysNavPaneGroups ON MSysNavPaneGroupCategories.Id = MSysNavPaneGroups.GroupCategoryID " & _
"WHERE (((MSysNavPaneGroupCategories.Name) " & CategorySelection & ") AND ((MSysNavPaneGroups.Name) " & GroupSelection & ") AND MSysObjects.Name " & ObjectSelection & " AND ((MSysNavPaneGroupCategories.Type)=4) AND ((MSysNavPaneGroups.[Object Type Group])=-1)) " & _
"GROUP BY MSysNavPaneGroups.GroupCategoryID, MSysNavPaneGroupCategories.Name, MSysNavPaneGroups.Id, MSysNavPaneGroups.Name, MSysObjects.Id, MSysObjects.Name, MSysObjects.Type " & _
"ORDER BY Min(MSysNavPaneGroupCategories.Position), Min(MSysNavPaneGroups.Position);"
DoCmd.RunSQL SQL
If DCount("*", "[" & ToMove & "]") = 0 Then Err.Raise 63 'Nothing to move
'Add the objects to their groups
DoCmd.RunSQL _
"INSERT INTO MSysNavPaneGroupToObjects ( GroupID, Name, ObjectID ) " & _
"SELECT TM.GroupID, TM.ObjectAlias, TM.ObjectID " & _
"FROM [" & ToMove & "] AS TM LEFT JOIN MSysNavPaneGroupToObjects ON (TM.ObjectID = MSysNavPaneGroupToObjects.ObjectID) AND (TM.GroupID = MSysNavPaneGroupToObjects.GroupID) " & _
"WHERE MSysNavPaneGroupToObjects.GroupID Is Null;"
'Add any missing NavPaneObjectIDs
DoCmd.RunSQL _
"INSERT INTO MSysNavPaneObjectIDs ( Id, Name, Type ) " & _
"SELECT DISTINCT TM.ObjectID, TM.ObjectName, TM.ObjectType " & _
"FROM [" & ToMove & "] AS TM LEFT JOIN MSysNavPaneObjectIDs ON TM.ObjectID = MSysNavPaneObjectIDs.Id " & _
"WHERE (((MSysNavPaneObjectIDs.Id) Is Null));"
SetNavGroup = True
EOFn:
On Error Resume Next
DoCmd.DeleteObject acTable, ToMove
On Error GoTo 0
DoCmd.SetWarnings True
Exit Function
SilentlyContinue: Resume EOFn
End Function

Vb.net and MySQL issue

When I click on save, I get the message:
You have an error in your SQL syntax;Check the manual that corresponds to your mySQL Server version for the right Syntax to use near 'idDrug=21' at line 21
Here is my code:
Private Sub cmdSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSave.Click
Dim i As Integer
Dim xid As Integer
Dim xQTY(0) As Integer
Dim xQTY_ID(0) As Integer
Dim xCount As Integer
Dim xCounter_ID(0) As Integer
'Dim sqlstrx(5) As String
xid = 0
If lstitems.Items.Count > 0 Then
If Split(Me.Text, " - ")(1) = "Add" Then
sqlSTR = "INSERT INTO orders (CustID, Cust_Name, order_date) " & _
"VALUES (" & txtcustid.Text & ", " _
& "'" & txtcustname.Text & "', " _
& "'" & Format(dttoday.Value, "yyyy-MM-dd") & "')"
ExecuteSQLQuery(sqlSTR)
sqlSTR = "SELECT * FROM orders ORDER BY order_no DESC"
ExecuteSQLQuery(sqlSTR)
xid = sqlDT.Rows(0)("order_no")
For i = 0 To lstitems.Items.Count - 1
sqlSTR = "INSERT INTO orders_detail (order_no, idDrug, DrugName, Unit_Cost, qty, totalcost) " & _
"VALUES (" & xid & ", " _
& lstitems.Items(i).Text & ", " _
& "'" & lstitems.Items(i).SubItems(1).Text & "', " _
& "'" & lstitems.Items(i).SubItems(2).Text & "', " _
& lstitems.Items(i).SubItems(3).Text & ", " _
& lstitems.Items(i).SubItems(4).Text & ")"
ExecuteSQLQuery(sqlSTR)
'UPDATE STOCKS
sqlSTR = "UPDATE stockbalances SET ItemQuantity = ItemQuantity -" & CDbl(lstitems.Items(i).SubItems(3).Text) & _
"WHERE idDrug =" & lstitems.Items(i).Text
ExecuteSQLQuery(sqlSTR)
Next
Else
'delete first
For i = 0 To UBound(deleteID)
ExecuteSQLQuery("DELETE FROM Orders_detail WHERE order_no =" & txtorderno.Text & " AND idDrug =" & deleteID(i))
sqlSTR = "UPDATE stockbalances SET ItemQuantity = ItemQuantity +" & Delete_QTY(i) & _
" WHERE idDrug =" & deleteID(i)
ExecuteSQLQuery(sqlSTR)
Next
For i = 0 To UBound(deleteID)
ReDim deleteID(i)
deleteID(i) = 0
Next
del = 0
'--
'If lstitems.Items.Count > 0 Then
For i = 0 To lstitems.Items.Count - 1
'MsgBox(stockID & " " & lstitems.Items(i).Text)
sqlSTR = "SELECT * FROM orders_detail WHERE order_no =" & stockID & " AND idDrug =" & lstitems.Items(i).Text
ExecuteSQLQuery(sqlSTR)
If sqlDT.Rows.Count > 0 Then
ReDim Preserve xQTY(i), xQTY_ID(i)
xQTY(i) = sqlDT.Rows(0)("QTY")
'xQTY_ID(i) = sqlDT.Rows(0)("Item_ID")
End If
'MsgBox(sqlDT.Rows(0)("QTY"))
Next
For i = 0 To lstitems.Items.Count - 1
'MsgBox(xQTY_ID(i))
If lstitems.Items(i).Index <= (UBound(xQTY)) Then
If CDbl(lstitems.Items(i).SubItems(4).Text) < xQTY(i) Then
'MsgBox(xQTY(i) - CDbl(lstitems.Items(i).SubItems(4).Text))
If xQTY(i) > 0 Then
sqlSTR = "UPDATE orders_detail SET qty =" & lstitems.Items(i).SubItems(4).Text & ", " _
& "totalcost =" & lstitems.Items(i).SubItems(3).Text * lstitems.Items(i).SubItems(4).Text & _
" WHERE Order_no =" & stockID & " AND idDrug=" & lstitems.Items(i).Text
ExecuteSQLQuery(sqlSTR)
'UPDATE STOCKS
sqlSTR = "UPDATE stockBalances SET ItemQuantity = ItemQuantity + " & (xQTY(i) - CDbl(lstitems.Items(i).SubItems(4).Text)) & _
" WHERE idDrug =" & lstitems.Items(i).Text
ExecuteSQLQuery(sqlSTR)
End If
ElseIf CDbl(lstitems.Items(i).SubItems(4).Text) > xQTY(i) Then
If xQTY(i) > 0 Then
sqlSTR = "UPDATE orders_detail SET qty =" & lstitems.Items(i).SubItems(4).Text & ", " _
& "totalcost =" & lstitems.Items(i).SubItems(3).Text * lstitems.Items(i).SubItems(4).Text & _
" WHERE order_no =" & stockID & " AND idDrug=" & lstitems.Items(i).Text
ExecuteSQLQuery(sqlSTR)
'UPDATE STOCKS
sqlSTR = "UPDATE Stockbalances SET ItemQuantity = ItemQuantity - " & (CDbl(lstitems.Items(i).SubItems(4).Text) - xQTY(i)) & _
" WHERE idDrug =" & lstitems.Items(i).Text
ExecuteSQLQuery(sqlSTR)
End If
End If
End If
Next
' End If
'search for new item
sqlSTR = "SELECT * FROM orders_detail WHERE order_no =" & stockID & " ORDER BY Order_Dtl ASC"
ExecuteSQLQuery(sqlSTR)
xCount = sqlDT.Rows.Count
For i = 0 To sqlDT.Rows.Count - 1
ReDim Preserve xCounter_ID(i)
xCounter_ID(i) = sqlDT.Rows(i)("idDrug")
' xCount = i + 1
Next
'check
If lstitems.Items.Count > xCount Then
For i = 0 To lstitems.Items.Count - 1
If i > UBound(xCounter_ID) Then
'MsgBox(lstitems.Items(i).Text)
sqlSTR = "INSERT INTO orders_detail (order_no, idDrug, DrugName, price, qty, totalcost) " & _
"VALUES (" & txtorderno.Text & ", " _
& lstitems.Items(i).Text & ", " _
& "'" & lstitems.Items(i).SubItems(0).Text & "', " _
& "'" & lstitems.Items(i).SubItems(1).Text & "', " _
& lstitems.Items(i).SubItems(2).Text & ", " _
& lstitems.Items(i).SubItems(3).Text & ", " _
& lstitems.Items(i).SubItems(4).Text & ")"
ExecuteSQLQuery(sqlSTR)
'UPDATE STOCKS
sqlSTR = "UPDATE stockbalances SET ItemQuantity = ItemQuantity -" & CDbl(lstitems.Items(i).SubItems(4).Text) & _
"WHERE idDrug =" & lstitems.Items(i).Text
ExecuteSQLQuery(sqlSTR)
End If
Next
End If
End If
Else
MsgBox("Can't save without details !!", MsgBoxStyle.Exclamation, xTitlename)
Exit Sub
End If
MsgBox("Record has been saved !!", MsgBoxStyle.Information, xTitlename)
sqlSTR = "SELECT distinct orders.order_no AS 'Order No.', Cust_Name as 'Customer Name', order_date AS 'Date', sum(totalcost) AS 'TOTAL DUE' FROM orders_detail " & _
"INNER JOIN orders ON orders_detail.order_no = orders.order_no " & _
"WHERE order_date ='" & Format(dttoday.Value, "yyyy-MM-dd") & "' GROUP BY orders.order_no, Cust_Name, order_date"
FillListView(ExecuteSQLQuery(sqlSTR), FrmORDERLIST.lstorder, 0)
Me.Close()
End Sub
It is impossible to fix all of your code and to be precise what is the exact cause of your error.
Suffice to say that you never should do a database application using that kind of string concatenation approach. Any of your text fields could cause the error because it contains single quotes or any of your date items could cause the error because it is not formatted how the database requires. (Same for decimals and other floating point values).
To solve this problems (and to avoid the dangerous Sql Injection scenarion) exists the parameterized queries approach.
So, just an example on what you need to do for every line of your sql commands
sqlSTR = "INSERT INTO orders_detail (order_no, idDrug, DrugName, " & _
"Unit_Cost, qty, totalcost) VALUES (" & _
"#id, #iddrug, #dname,#unit, #qty, #total)"
Using cmd = new MySqlCommand(sqlStr, connection)
cmd.Parameters.AddWithValue("#id", xid)
cmd.Parameters.AddWithValue("#idrug", Convert.ToInt32(lstitems.Items(i).Text))
cmd.Parameters.AddWithValue("#dname", lstitems.Items(i).SubItems(1).Text)
cmd.Parameters.AddWithValue("#unit", lstitems.Items(i).SubItems(2).Text)
cmd.Parameters.AddWithValue("#qty", Convert.ToDecimal(lstitems.Items(i).SubItems(3).Text ))
cmd.Parameters.AddWithValue("#total", Convert.ToDecimal(lstitems.Items(i).SubItems(4).Text))
cmd.ExecuteNonQuery()
End Using
Notice how, in a parameterized query, you could specify the datatype of the value passed for the parameter using the Convert.ToXXXXX method. In this way the framework code could prepare the appropriate formatting of your values to be passed to the database engine.
Not to mention the now readable query text.

VBA: Syntax error when passing numeric value to a field using UPDATE

Here is my code
Dim orderid As Long
orderid = DMax("Number", "Orders", "") + 1
DoCmd.RunSQL "Update Order_temp " _
& "Set Number = " & orderid & ", Name = '" & Me.Textbox & "' " _
& "WHERE (Name = '*')"
It works fine if it's only like this
Dim orderid As Long
orderid = DMax("Number", "Orders", "") + 1
DoCmd.RunSQL "Update Order_temp " _
& "Set Name = '" & Me.Textbox & "' " _
& "WHERE (Name = '*')"
Thank you in advance.
try using square brackets when referencing fields of a table like so :
DoCmd.RunSQL "Update [Order_temp] " _
& "Set [Number] = " & orderid & ", [Name] = '" & Me.Textbox & "' " _
& "WHERE ([Name] = '*')"
It will help avoiding conflicts on reserved words like Number.
Also I would edit a bit the other line as well :
orderid = Nz(DMax("Number", "Orders", ""),0) + 1
In order to avoid a Null exception.

change character in all text fields

I need your help. I woulod like to change one char by another but in all database and i have several table and fields. So i'm building a function in VB but that change nothing and i have no error. I think that my condition is false but i don't see how to correct it :/
Public Sub updateField()
Dim db As DAO.Database, td As DAO.TableDef, field As DAO.field
Dim rs As DAO.Recordset, sSQL As String, sData As String
Set db = CurrentDb
Change = "\"""
replaced = """"
'each table in db
For Each tbd In db.TableDefs
'each field in table
For Each fld In tbd.Fields
'check if String Data have my character
If InStr(1, fld.Name, Change) Then
sSQL = "UPDATE " & tbd.Name & " SET " & fld.Name & " = replace([" & fld.Name & "], " & Change & ", " & replaced & ")"
db.Execute sSQL
End If
Next
Next
End Sub
EDIT :
I finally find what's wrong. if some people are interested :
Set db = CurrentDb
Change = "\"""
replaced = """"
'each table in db
For Each tbd In db.TableDefs
'each field in table
For Each fld In tbd.Fields
If Left(tbd.Name, 4) <> "MSys" And Left(tbd.Name, 4) <> "~TMP" Then
If fld.Type = dbText Or fld.Type = dbMemo Then
sSQL = "UPDATE " & tbd.Name & " SET " & fld.Name & " = replace([" & fld.Name & "],'" & Chr(92) + Chr(34) & "','" & Chr(34) & "')"
db.Execute sSQL
'Debug.Print (sSQL)
End If
End If
Next
Next
Thx for your help guys ;)
If it should help there my solution :
Public Sub updateField()
Dim db As DAO.Database, td As DAO.TableDef, field As DAO.field
Dim rs As DAO.Recordset, sSQL As String, sData As String, change As String, replace As String
change = "\'"
replace = "'"
' simple quote = 39
' doulbe quote = 34
' antislash = 92
' retour chariot = 13
' n = 110
' r = 114
Set db = CurrentDb
'each table in db
For Each tbd In db.TableDefs
'each field in table
For Each fld In tbd.Fields
If Left(tbd.Name, 4) <> "MSys" And Left(tbd.Name, 4) <> "~TMP" Then
If fld.Type = dbText Or fld.Type = dbMemo Then
' \r\n
'sSQL = "UPDATE " & tbd.Name & " SET [" & fld.Name & "] = replace([" & fld.Name & "],'\r\n','" & Chr(13) & Chr(10) & "');"
' \"
'sSQL = "UPDATE " & tbd.Name & " SET [" & fld.Name & "] = replace([" & fld.Name & "],'" & Chr(92) + Chr(34) & "','" & Chr(34) & "');"
'db.Execute sSQL
sSQL = "UPDATE " & tbd.Name & " SET [" & fld.Name & "] = replace([" & fld.Name & "],'\''','''');"
db.Execute sSQL
'Debug.Print (sSQL)
End If
End If
Next
Next
End Sub
That's works for me ;)