Add if the record is not existing - sql

I'm trying to create a program that will Import a spreadsheet and append/update it to my MainDB,
I'm done with the Update Process, where if field(JobName) is found in to Main database, then I will update the record/s.
Next step is, to check if the record is existing, if not then I need a code to add that, Please help!
ConnectdbMain 'Sub Where I connect to my Maindb
Connectdbtemp 'Sub Where I connect to Tempdb which I imported to an excelfile
With rs
While Not .EOF
rst.MoveFirst
While Not rst.EOF
If .Fields(Combo.Value) = rst.Fields(Combo2.Value) Then 'the user is allowed which field is to compare and append I use combo box to filter choices.
.Edit
.Fields(Combo3.Value) = rst.Fields(Combo4.Value)
.Update
End If
rst.MoveNext
Wend
.MoveNext
Wend
End If
CloseDbMain
Set rst = Nothing
Dbs.Execute "DROP TABLE TempTable" 'I drop it like a trash since its already appended :)
ClosedbTemp
End With

Hmm... I don't know about you. But if it's a excel spreadsheet I would use OLE DB to read the spreadsheet datasource and use SQL query to select all the DISTINCT JobName in the spreadsheet first.
And I would also use for in loop for every of the spreadsheet distinct name to execute a select statement in your main database with VBA to....
select count(JobName) from table where JobName = the_job_name_in_excel
Then use an If Then to detect if the returned row count = 0 then do an update statement.
Of course there's a lot more so you need to read on how to create a database connection to your main database and spreadsheet if you want to use my method. The methods in creating these connections is easily available out there.

Related

VBA in MS Access: how to accelerate a loop operation on a recordset

In a database under my maintenance (MS Access 2010) I use a VBA procedure for cleaning up records, concretely: setting values in a field from "yes" to "no". The procedure loops through all records and sets the values in the respective field as required.
My database has about 900 records so far. Not too many, one should think.
My problem: the VBA procedure operates very slowly. On my current machine I have to wait for about 10 seconds until the loop has gone through the 900 records. That's impractical in everyday work.
What I need: I am looking for ways to speed this up, either through improvements to the code, or through a completely different approach.
Here is my procedure:
Private Sub WipeSelectionMarks_Click()
'Remove any filter that might be set to reduce the number of records in
'the form - We want here to operate on all records in the database!
Me.Filter = ""
Me.FilterOn = False
'Don't know if we really need two commands here; but at least it works
'Operate on a recordset that holds all the records displayed in the form
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
rs.MoveFirst
Do Until rs.EOF
With rs
.Edit
!Int_IwSelectMove = False
.Update
End With
rs.MoveNext
Loop
'Message box with info what has been done
MsgBox "A total of " & rs.RecordCount & " records were updated by wiping the Move mark"
'Cleaning up
Set rs = Nothing
Me.Refresh
End Sub
Note 1: if a solution would be using an SQL command instead, I will be grateful for practical hints or examples. I use SQL commands at many places, still, getting put on the right track here would be helpful.
Note 2: Or can the VBA procedure be rewritten in a way that only records where the field in question has value "yes" are processed (these are usually only 20-30 of the 900), and those with "no" are left out?
You can use the UPDATE command:
CurrentDb.Execute "UPDATE YourTable SET Int_IwSelectMove = False"
can the VBA procedure be rewritten in a way that only records where
the field in question has value "yes" are processed
Indeed, and that may very well be the fastest method, as you will not have to requery the form:
With rs
Do Until .EOF
If !Int_IwSelectMove.Value = True Then
.Edit
!Int_IwSelectMove = False
.Update
End If
.MoveNext
Loop
.Close
End With
Or you could use FindFirst or a filtered recordset. Running SQL on the recordset of a form is usually the last option.

Identifying exact location of data entry issues when bulk copying or importing from excel to access

One of the requirements of a project that I have is to allow users to import or copy and paste in bulk a few hundred rows from excel to access. However, there is a reasonable chance due to human error that there will be some data validation issues between the imported data and the table structure/referential integrity rules. I would like to be able to identify exactly the field/s and record/s where these issues are occuring so that I can point them out to the user for correction.
As such the standard error essages like 'you cannot add or change a record because a related record is required in...' or 'data type mismatch in criteria or expression' are not descriptive enough to the exact location of the problem so even if I catch them I can't really give a better descriptor anyway
I am debating importing to a completely free text temporary table, then looping an insert to move one row at a time from the temp table to the properly validated table and using dbfailonerror to catch issues on individual records that need correction (the user needs to correct them I can't do this through code)
My question is whether this is a reasonable approach, is there a better/easier way, or a way to get a more specific error from access rather than using a loop?
Thanks
There are 2 ways to do this. I'm not sure what method you are using to do the import but if is as simple as copying rows from the excel sheet to the table Access will generate a Paste_errors table that will show the rows it couldn't import. The wizard will do the same thing but I think its prone to crashing.
The way I typically do it is actually have the end user use an excel template with a VBA backend that does the uploading. You can check each value conditionally and give a better descriptive alert and/or shuttle any defective rows to a temporary table for you to review.
You can do this the opposite way and do the import through Access VBA but that would be more coding since you would have to create an Excel object in code, open the sheet, etc.
I setup a Quickbooks export of a accounts receivable table by creating a User DSN on the local machine pointing to the Access file, opening an ADO recordset and looping through the rows one column at a time applying logic to each row.
Quickbooks would ask for an existing file to dump the data into so I made that a template file on the network. It sounds like your users may have to enter directly into the spreadsheet so you would have to distribute the template but the results are the same.
Example of Looping through the sheet and validating rows
Create a DSN file to the database and store it on a shared drive, this way you don't have to hardcode the string and if you need to change something, you only have to change the dsn file instead of redistributing templates.
Public Sub Upload
'Declare the main recordset that the records will be uploaded to.
Dim rstUpload as New Adodb.Recordset
'Declare a utility recordset object that you can reuse to check referential tables
Dim rstCheck as New Adodb.recordset
'Declare a utility command object that you can reuse to check referential tables
Dim SQLCommand as New Adodb.Command
'Declare the connection object to the database
Dim dataConn as New Adodb.Connection
'A tracking flag if you find something in a row that won't upload
Dim CannotUpload as Boolean
'Open the connection to the access database
dataConn.Open "\\Server\Share\Mydatabase.dsn" 'Your dsn file'
Set SQLCommand.ActiveConnection = DataConn
rst.Open "yourTable", dataConn, adOpenDynamic, adLockBatchOptimistic
For i = 1 to 100 ' Rows
*You may want to do a pass through the rows so you can get an accurate count, usually just loop through the rows until a column that must have data is blank. If your users are skipping rows that is going to be a problem.
rstUpload.AddNew
'Set the tracking Flag to False indicating you can upload this row, this will be changed if any field cannot be validated
CannotUpload = False
'First Column/Field: 'Non critical field, any value will do
rstUpload("Field1").Value = Range(i,1).Value '
'Second Column/Field has a referential integrity constraints
'Run a query against the table that has the values you are trying to validate.
SQLCommand.CommandText = "Select IDField From YourTable where ID = " & Range(i,2).Value
Set rstCheck = SQLCommand.Execute
'Check if any records were returned, if none than the value you are checking is invalid
If rstCheck.RecordCount > 0 Then 'we matched the value in the cell
rstUpload ("Field2").Value = Range(i,2).Value
else
'Design a flagging method, maybe highlight the cell in question
CannotUpload = True
End if
....continue through your columns in the same fashion, reusing the SQLCommand Object and the Utility recordset when you need to lookup something in another table
'After last column
If CannotUpload = False Then
'Nothing triggered the flag so this row is good to go
rstUpload.Update
Else
'Cannot Upload is true and this row won't be uploaded
rstUpload.Cancel
End If
Next i
dataconn.Close
set dataConn = Nothing
set rstUpload = Nothing
set rstCheck = Nothing
set SQLCommand = Nothing

How do I go to my last entered record in a large access form?

I have a large Access database of items (70,000+) with a one-to-many relationship. Each record has a set of analytical results e.g.
record 1 has sample IDs sample1: chlorine=1mg/l, sample 2: chlorine=2.3mg/L;
record 2 has sample IDs sample1: chlorine=3.8mg/L.
I have created a form to begin entering data, but I would like to create a macro button that will take me to the last record entered. Once I start getting to record #100+, I do not want to have to remember the number of the last record I was on.
To complicate this issue, some records do not have analytical data and will be null.
I was thinking of a macro that will search for null records. Once it finds a null record, it will double check that it isn't a previously entered record that happened to be null by checking the next 50 or so records and make sure each 50 records ahead of it are also null. Could someone give me some guidance on how to do this with a macro? Once I have a working macro, I know how to apply it to a button on my form.
Thank you.
You could create a table to store a bookmarked record number from your form:
Then set your form up so you have a command button to bookmark your place:
Then on that button's click event you could take the record number of the current record and put it in your bookmark table for later:
Private Sub cmdSavePlace_Click()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim sql As String
Set db = CurrentDb
sql = "DELETE * FROM tblLastAccessedRecord"
db.Execute sql
Set rs = db.OpenRecordset("tblLastAccessedRecord")
With rs
rs.AddNew
rs!RecordNumber = Me.CurrentRecord
rs.Update
End With
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
You can then add a command button to your form to move you to the next record after the saved bookmark using the record number that's currently stored in the table:
The following VBA should jump you to the record after (+1) the one that's been stored in your bookmark table:
Private Sub cmdGoToNext_Click()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("tblLastAccessedRecord")
DoCmd.GoToRecord acDataForm, "frmDataEntry", acGoTo, rs!RecordNumber + 1
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
So, for example, if I bookmark record 11...
...this is now stored in our table:
So if we close the form for the day, and come back to form tomorrow we might be back at record 1...
...but if we click our go to bookmarked record command button we'll be taken to record 11+1, i.e. record 12:
Wow, out of the box answer and what I was looking for. The question required a button and one was provided.
Just to build on this a little though, for my purposes, there would be little overhead to a macro / code being fired from the, ummm, afterUpdate control I guess, on the form being edited, that updates the value of the record in tblLastAccessedRecord. Unless OnUnload still has access to the record value, in which case you can set it automatically when you close the form, but I'm not sure it will have.

Importing specific Access table data into Excel using Excel as the front end

I am trying to store and retrieve data that is entered into Excel into Access. I am an Access newbie and already have an Excel program on the front end, leading me to drive the import from Excel. I have successfully figured out how to save my Excel Named Range into the desired Access table, but now I need to figure out how to pull specific data from that Access table back into Excel. I know I can simply use the Get External Data feature from Excel to import the entire Access table into Excel, but I need to be able to only import a specific portion of the table into Excel based upon a predetermined set of parameters. Is this possible to do?
As a background to the program, basically it stores data from part number runs. Not only do I need to save new part runs into an Access database (which I figured out), but I also need to be able to pull previous part number runs from Access back into Excel to perform further analysis. That is why I need to figure out how to import only a specific portion of the table. I'm not sure what code, if any, I can post since I'm basically looking for code from scratch; but if there's any code you think you need from my Excel program I'm happy to provide it. Thanks for your help. Below is the code:
Sub GetSpecData()
Application.ScreenUpdating = False
'*******************************************************************************
'Open the connection to the data source.
Set Connection = New ADODB.Connection
Connection.Open "Provider=Microsoft.Jet.OLEDB.4.0; " & "Data Source=\\Server2013\network_shared\QC SHARED\Databases\P&Q_Tracking_Data_Storage.mdb;"
'*******************************************************************************
'Create the new RecordSet.
Set Recordset = New ADODB.Recordset
With Recordset
'Define the appropriate Filter(s) and notify the user of the selection criteria.
Src = "Select * from Raw_Data where Tag = 'GHI' "
Src = Src & "or Tag = 'DEF' "
Src = Src & "or Tag = 'LMN'"
.Open Source:=Src, ActiveConnection:=Connection
'Write the field names.
For ODCol = 0 To .Fields.Count - 1
Tracking.Sheets("Selected Past Data").Range("B7").Offset(0, ODCol).Value = .Fields(ODCol).Name
Next
'Write the recordset.
Tracking.Sheets("Selected Past Data").Range("B7").Offset(1, 0).CopyFromRecordset Recordset
End With
Set Recordset = Nothing
Connection.Close
Set Connection = Nothing
'*******************************************************************************
'Create and format the table from the Recordset.
With Tracking.Sheets("Selected Past Data")
DataLastRow = .Range("A" & Rows.Count).End(xlUp).row
.ListObjects.Add(xlSrcRange, Range("B7:M" & DataLastRow), , xlYes).Name = "INC2tbl"
.ListObjects("INC2tbl").ShowTotals = True
End With
Application.ScreenUpdating = True
'*******************************************************************************
End Sub
After googling the suggestion in the comment below, I have a couple questions. First, the code above seems to filter access data by three keys: GHI, DEF, and LMN. Am I interpreting that correctly? Second, where it says "Select * from Raw_Data where Tag = 'GHI' ", since that's in quotes, that's not actual code that will be executed, correct? That's simply a prompt or something like it, correct?
SELECT * FROM TABLE; OUTPUT TO TABLEName.EXL
FORMAT sql;
First, the code above seems to filter access data by three
keys: GHI, DEF, and LMN. Am I interpreting that correctly?
Second,
where it says "Select * from Raw_Data where Tag = 'GHI' ", since
that's in quotes, that's not actual code that will be executed,
correct? That's simply a prompt or something like it, correct?
First and second questions relate closely, so I'll answer as one. The basic idea here is that there is a connection to the database you defined (in the Connection.Open statement). The connection itself does nothing then that; establish a connection. The actual communication with the database is done in a specific language, named SQL (there are many dialects, but for simplicity sake, call it SQL for now). So your code in in the VBA language, but the communication with the database is done in SQL. The VBA code has to produce SQL statements (and those are strings, so you need the quotes). That's what the Src variable holds; and SQL statement. In this case:
"Select * from Raw_Data where Tag = 'GHI' or Tag = 'DEF' or Tag = 'LMN'"
I think this is not the place to teach you SQL, but there is plenty information on the net about it. What this statement does is:
select all columns from table "Raw_Data", but only those rows of data that has 'GHI', 'DEF' or 'LMN' in the Tag column.
So to receive all the data from table "part_numbers", you would have to use:
"SELECT * FROM part_numbers;"
And if you need to import only columns "col_1" and "col_2", you would use:
"SELECT col_1,col_2 FROM part_numbers;"
And if you need to import only columns "col_1" and "col_2", and only rows with "part_id" lower than 1000, you would use:
"SELECT col_1,col_2 FROM part_numbers WHERE part_id < 1000;"
That's it really. Now if your recordset (think of it as an array that holds the data you asked for) has queried the database, you can loop it to parse the data. Something like:
Set Recordset = Connection.Execute(Src)
Do until Recordset.EOF
debug.print Recordset!col_1
Recordset.movenext
loop
Again, google something like: "vba excel adodb access", and you'll hit plenty examples.
After researching SQL code formatting more I have made more sense of the subject. Thanks for the help.

How to run a SQL select statement in VB

I have been looking around but can't seem to find out how to do this.
I'm trying to execute a SELECT sql statement in VB that takes in a parameter from a form. For example the user selects a From and a To date and the SQL should take what they selected.
I know that you cannot use the DoCmd.Execute method for SELECT SQL so I would need to open the record set - but how? This is what I have tried so far
Dim recordSet As DAO.recordSet
Dim SQL As String
SQL = "SELECT * FROM tblWebMeetingData"
Set recordSet = CurrentDb.OpenRecordset(SQL)
'More code in here
recordSet.Close
Set recordSet = Nothing
Because this executes without an error I assume it's actually getting the results - so is there a way to see what it is actually returning?
Thanks
First: It's a good advice to rename the recordset to rs, for example, because "recordset" is a reserved name. This is misunderstandable.
This recordset contains the records you queried by your SQL statement. You may access those data by rs.fields("fieldname").value. Move to the next recordset with rs.movenext.
To incorporate the form's control value I use the way to build the full SQL statement prior to opening the recordset. Say the form is named "myform" and the control "mycontrol", you may write some kind of
SQL = "SELECT * FROM tblWebMeetingData WHERE myfield = " & forms!myform.mycontrol.value
Please be sure the form only contains valid values, because any wrong formatted value will directly lead to an SQL execution error.
I hope it was this, what you wanted.
Here you have come sample code about iterating trought RecordSet and using values from it( I hope it helps a bit):
Dim i As Integer
Do While Not rs.EOF
Sheets("D_" & day).Cells(i, 1) = rs.Fields(0).Value
Sheets("D_" & day).Cells(i, 2) = rs.Fields(1).Value
rs.MoveNext
i = i + 1
Loop
rs.Close