I want your kind help to give a solution to match between two tables and return unmatched recorda with a field specify which field was unmatched.
Take a note that each table including more than 30 fields.
You can use recordsets but if your tables are long this might take a while. This is absolutely not optimized, but considering how little information you provided, I don't want to invest a whole lot of time.
I am assuming your tables are identical in structure, sorted identically, and have the same number of records. If not, feel free to adapt this however you see fit, but you should be able to get the idea of what I am doing.
It will output the field and row number of Table1 in the immediate window when a mismatch is found. You could also insert it into a temp table if you want to recover all of the field values, but again, I don't want to go that far. So this has limitations:
Public Function FindMisMatches(Table1 As String, Table2 As String)
Dim db As DAO.Database
Dim rs1 As DAO.Recordset
Dim rs2 As DAO.Recordset
Dim i As Integer
Dim Row As Integer
On Error GoTo PROC_ERR
Set db = CurrentDb
Set rs1 = db.OpenRecordset(Table1, dbOpenSnapshot, dbReadOnly)
Set rs2 = db.OpenRecordset(Table2, dbOpenSnapshot, dbReadOnly)
rs1.MoveFirst
rs2.MoveFirst
Row = 1
Do Until rs1.EOF Or rs2.EOF
'Assuming both tables have identical structure
For i = 1 To rs1.Fields.Count - 1
If rs1.Fields(i).Value <> rs2.Fields(i).Value Then
Debug.Print "Mismatch in field " & rs1.Fields(i).Name & " on row " & Row
End If
Next i
rs1.MoveNext
rs2.MoveNext
Row = Row + 1
Loop
Debug.Print "End of recordset"
Set rs1 = Nothing
Set rs2 = Nothing
Set db = Nothing
Exit Function
PROC_ERR:
MsgBox "Error: " & Err.Number & "; " & Err.Description
Set rs1 = Nothing
Set rs2 = Nothing
Set db = Nothing
End Function
Related
I am trying to erase some data (values = 0) from a field in access, but without knowing the name, I only know the position of the field in the database (13Âșcolumn) . I thought it would be very simple, but after many tries I still can't manage to find a solution and I am starting to doubt if it's even possible.
So this is the code that I am using:
Sub Erasevalues0()
Dim strQValue As String
Dim i As Integer
Dim db As DAO.Database
Dim sql13 As String
Set db = CurrentDb
sql13 = db.TableDefs("TableName").Fields(13).Name
strQValue = "DELETE FROM TableName WHERE sql13=0;"
db.Execute strQValue
End Sub
I even tried something like:
strQValue = "DELETE FROM TableName WHERE Fields(13)=0;"
But nothing seems to work. Any suggestions?
I think you need to loop through the recordset. The following should work
Sub RemoveZeros()
Dim db As Database
Dim rs As Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("Table1", dbOpenDynaset)
rs.MoveFirst
With rs
Do Until .EOF
If .Fields(13) = 0 Then .Delete 'Delete row if column 13 = 0
.MoveNext 'Move to next record
Loop
End With
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
Not sure if there is a direct way to use the index of a field. A workaround:
query = "SELECT * FROM TableName"
columnName = CurrentDb.OpenRecordset(query).Fields(13).Name
strQValue = "UPDATE TableName " & _
"SET " & columnName & "=''"
I am trying to compare two recordsets in access VBA to check whether the values within the two tables are the same or whether they differ. Both recordsets have the same structure (field headings) and record IDs and I'm trying to check whether a field value for a record matches the corresponding field value in the second recordset. The record ID field name is MATNR.
I think I've managed to loop through the records and fields for the 1st recordset but I'm unsure how to loop through and compare these records with the second. Also, is there a smarter way to compare the recordsets other than If rs1.Fields(fld.Name) = rs2.Fields(fld.Name)
Any help will be greatly appreciated.
Public Sub VerifyRecords()
Dim rs As DAO.Recordset
Dim rs1 As DAO.Recordset
Dim rs2 As DAO.Recordset
Dim rs3 As DAO.Recordset
Dim fld As DAO.Field
Dim sSQL As String
Dim sSQL1 As String
Dim sSQL2 As String
Set rs = CurrentDb.OpenRecordset("R2_Tables_to_Compare1") 'This table lists the upload tables to query and their corresponding target tables
Set rs3 = CurrentDb.OpenRecordset("RecordValueComparisonResults") 'Write the results of the record vlaue comparison to here
'**************************************************************************************
'This SQL statement selects all records from the upload table
sSQL = "SELECT * "
sSQL = sSQL & " FROM " & rs(0)
Set rs1 = CurrentDb.OpenRecordset(sSQL)
'**************************************************************************************
'This SQL statement selects only those records that are applicable in the target table
sSQL1 = "SELECT " & rs(1) & ".* FROM " & rs(1) & " INNER JOIN " & rs(0) & " ON " & rs(1) & ".MATNR = " & rs(0) & ".MATNR"
Set rs2 = CurrentDb.OpenRecordset(sSQL1)
'**************************************************************************************
Do While Not rs1.EOF
For Each fld In rs1.Fields
If rs1.Fields(fld.Name) = rs2.Fields(fld.Name) Then
Debug.Print rs1.Fields("MATNR"), rs2.Fields("MATNR"), fld.Name, rs1.Fields(fld.Name), rs2.Fields(fld.Name)
End If
Next fld
rs1.MoveNext
Loop
rs.Close
rs1.Close
rs2.Close
rs3.Close
Set rs = Nothing
Set rs1 = Nothing
Set rs2 = Nothing
Set rs3 = Nothing
End Sub
Below are two options, although the QUERY OPTION is faster and better practice when working in Access and any relational DB:
QUERY OPTION: This query could be passed into a recordset and the recordset would contain only the matching values between the fields in the two tables. Then you could loop through that new recordset and print or process as necessary using a single loop.
SELECT column_name FROM table1 INNER JOIN table2 ON table1.column_name = table2.column_name;
LOOP OPTION: If you are intent on looping through both recordsets, use this code. There is probably a more efficient way to do this, especially since this method uses four nested loops which is a no-no. I would highly recommend the QUERY OPTION.
While Not rs1.EOF
While Not rs2.EOF
For Each fld1 in rs1.Fields
For Each fld2 in rs2.Fields
If rs1.Fields(fld1.Name) = rs2.Fields(fld2.Name) Then
Debug.Print rs1.Fields("MATNR"), rs2.Fields("MATNR"), fld1.Name,
rs1.Fields(fld1.Name), rs2.Fields(fld2.Name)
End If
Next fld2
Next fld1
rs2.MoveNext
Wend
rs2.MoveFirst
rs1.MoveNext
Wend
I'm trying to add several new columns to a table that already exists in Access 2007 or 2010 with a query. Right now my code looks like this (yes, I'm terribly new to this):
ALTER TABLE AC_PROPERTY
ADD JAB_1 double,
JAB_2 double,
JAB_3 double;
This correctly adds the three columns when none of them already exist, but if any of them exist I get an error message and the query fails to run. I need it to add each columns only if it does not exist. Can anyone please help with what my code should look like to check if each column exists before trying to add it?
NOTE: I would just do 3 queries for each column, but I actually need to add 20+ columns. This is just a simple example of my actual use.
Thanks a billion!
Here is some old code.... it would be better to just check all fields in the same subroutine rather than opening/closing the DB, TDF, etc.
Option Compare Database
Option Explicit
Function Check_If_Exists()
Dim strStatus As String
' Add calls for the fields you want to append
strStatus = Add_Field("MyFLd2", "Double")
If strStatus = "Exists" Then
Debug.Print "field present"
ElseIf strStatus = "Added" Then
Debug.Print "field added"
End If
End Function
Function Add_Field(strFN, strType) As String
Dim db As DAO.Database
Dim td As DAO.TableDef
Dim fd As DAO.Field
Dim strSQL As String
On Error GoTo Error_Trap
Set db = CurrentDb
Set td = db.TableDefs("Table1")
' ' List all field names
' For Each fd In td.Fields
' Debug.Print fd.Name
' Next fd
If IsNull(td.Fields(strFN)) Then
Add_Field = "Exists"
End If
Set fd = Nothing
Set td = Nothing
Set db = Nothing
Exit Function
Error_Trap:
Debug.Print Err.Number & vbTab & Err.Description
If Err.Number = 3265 Then
Add_Field = "Added"
strSQL = "alter table Table1 ADD " & strFN & " " & strType & ";"
db.Execute strSQL
db.TableDefs.Refresh
End If
Exit Function
Resume
End Function
I have a section of code which creates a new table and then attempts to copy the record set values into the table. The only problem is this it is quite slow and access shows the loading symbol whilst it is executing this insert section below. Currently this problem is occurring inserting 500 records, but I will need to insert around 10,000 to 20,000 when I get a final data set.
I = 1
DoCmd.SetWarnings False
RecordSet1.MoveFirst
Do While Not RecordSet1.EOF = True
SQL = "INSERT INTO " & FullName & " ("
For Each field In RecordSet1.fields()
SQL = SQL & " " & Replace(field.Name, ".", "_") & ","
Next field
SQL = SQL & "ValidationCheck)"
SQL = SQL & " VALUES("
For Each field2 In RecordSet1.fields()
SQL = SQL & "'" & field2.Value & "',"
Next field2
SQL = SQL & Matches(I) & ")"
DoCmd.RunSQL (SQL)
RecordSet1.MoveNext
I = I + 1
Loop
What I want to know is, is there any way I can speed this up? Or are there better approaches?
(What I am trying to do is create a table at run time with a unique set of fields from a RecordSet and add an extra column with a Boolean value stored in Match array for each Record). The creation works fine, but the insertion code above is very slow.
Yes, use DAO. So much faster. This example copies to the same table, but you can easily modify it so copy between two tables:
Public Sub CopyRecords()
Dim rstSource As DAO.Recordset
Dim rstInsert As DAO.Recordset
Dim fld As DAO.Field
Dim strSQL As String
Dim lngLoop As Long
Dim lngCount As Long
strSQL = "SELECT * FROM tblStatus WHERE Location = '" & _
"DEFx" & "' Order by Total"
Set rstInsert = CurrentDb.OpenRecordset(strSQL)
Set rstSource = rstInsert.Clone
With rstSource
lngCount = .RecordCount
For lngLoop = 1 To lngCount
With rstInsert
.AddNew
For Each fld In rstSource.Fields
With fld
If .Attributes And dbAutoIncrField Then
' Skip Autonumber or GUID field.
ElseIf .Name = "Total" Then
' Insert default value.
rstInsert.Fields(.Name).Value = 0
ElseIf .Name = "PROCESSED_IND" Then
rstInsert.Fields(.Name).Value = vbNullString
Else
' Copy field content.
rstInsert.Fields(.Name).Value = .Value
End If
End With
Next
.Update
End With
.MoveNext
Next
rstInsert.Close
.Close
End With
Set rstInsert = Nothing
Set rstSource = Nothing
End Sub
For multiple inserts in a loop, don't use SQL INSERT statements. Instead use a DAO.Recordset with .AddNew.
See this answer: https://stackoverflow.com/a/33025620/3820271
As positive side effects, your code will become better readable and you don't have to deal with the multiple formats for different data types.
For Each field In RecordSet1.Fields
rsTarget(field.Name) = field.Value
Next field
I made a query to get Max value of a certain column
sSQLmax = "SELECT MAX([tablename]!rowname) as MaxNum FROM [tablename]"
I want to use MaxNum value. I tried it in a Msgbox and gave me a blank value. I tried all these:
MsgBox "MaxNum" & MaxNum
MsgBox "MaxNum" & sSQLMAX.MaxNum
MsgBox "MaxNum" & sSQLMAX!MaxNum
More of the code
Dim db As DAO.Database, rst As DAO.Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset(sSQLmax)
but none works, Im sure its simple but it escapes me
With your code you are only setting a variable to a string. You are not actually doing anything with it. This is probably more of what you are looking for:
Dim db As DAO.Database, rst As DAO.Recordset, sSQLmax As String
sSQLmax = "SELECT MAX([tablename].rowname) as MaxNum FROM [tablename]"
Set db = CurrentDb
Set rst = db.OpenRecordset(sSQLmax, dbOpenDynaset)
If (rst.RecordCount <> 0) Then
rst.MoveFirst
MsgBox "MaxNumber: " & rst.Fields("rowname")
End If
Try the DMax function
Dim result as String
result = DMax("[COLUMN NAME]", "[TABLE NAME]")