Microsoft Access insert query - ms-access

Access table Allowances_3_15_18 has 5 columns. I want to insert a calculated field from a form EmployeeSalary) into one of the columns Amount in the table.
Each value will link with the relevant primary ID's from the form and the table which are the same JobID. How do I do this in VBA?
I currently have done it in the afterUpdate event in the property sheet.
Private Sub ProjectedDollarAmount_AfterUpdate()
Dim strSQL As String
Dim ProjectedDollarAmount As Currency
strSQL = "INSERT INTO [Allowances_3_15_18] ([Amount]) VALUES (" & _
PrepareSQLNumber(Me.ProjectedDollarAmount) & ") WHERE JobID = " & _
PrepareSQLNumber(Me.JobID) & ";"
Call ExecuteMyCommand(strSQL)
End Sub

You need to get away from SQL concatenation and start using parameters.
Create a query with two parameters, the amount to be inserted and the JobId. The query's SQL should be something like this:
PARAMETERS [prmAmount] Currency, [prmJobId] Long;
UPDATE [Allowances_3_15_18] SET [Amount] = [prmAmount]
WHERE JobID = [prmJobId];
Then in code, simply pass the parameter values and execute the above query:
Sub Add()
With CurrentDb().QueryDefs("qryName")
.Parameters("[prmAmount]").Value = PrepareSQLNumber(Me.ProjectedDollarAmount)
.Parameters("[prmJobId]").Value = PrepareSQLNumber(Me.JobID)
.Execute dbFailOnError
End With
End Sub
You need to change the qryName to the actual name of the query.
You can read more about parameter queries here.

Related

How to retrieve value from database and display in textbox

I am using vb6, and the database is mysql. There is this table called "absen", it has a field called "tglabsen" which storing dates in this format : dd/mm/yyyy. I tried to find records according to the date.
eg. find records who have dates between 01/01/2017 to 01/02/2017
My question is how to store the number in a variable, and then display it in a textbox? What I tried so far, I tested this :
number = "Select count(*) from absen where tglabsen >='" & DTPicker1 & "' and tglabsen <='" & DTPicker2 & "'"
KON.Execute number
txtjumlahabsen = number
But the textbox (txtjumlahabsen) is just showing the sql query above.
KON.Execute just executes the sql statement you stored in your number variable. It doesn't update the variable with the data, which is why your textbox is showing the sql statement.
You need to open a recordset to retrieve the data:
Dim rs as New Recordset
Dim countVal as Integer
number = "Select count(*) from absen where tglabsen >='" & DTPicker1 & "' and tglabsen <='" & DTPicker2 & "'"
rs.Open number, KON, adOpenForwardOnly, adLockReadOnly
If Not rs.EOF then
countVal = rs(0).Value
End If
rs.Close
txtjumlahabsen.Text = countVal
If your sql statement is successful, the value from count(*) will be applied to the countVal variable. If it is not successful, countVal will remain at zero.

MS Access add/update query result to an existing table base on its ID

I followed the tips by others to produce an access query.
I have two tables. See figure1. And the result is figure2.
Figure1
http://img.libk.info/f1.png http://img.libk.info/f1.png
Figure2
http://img.libk.info/f2.png http://img.libk.info/f2.png
The method to generate the result query is solved in another question.
The query script :
TRANSFORM Nz(Count([number]),0) AS CountValue
SELECT Table1.ID
FROM Table1, Table2
WHERE (((Table2.number) Between [table1].[start] And [table1].[end]))
GROUP BY Table1.ID
PIVOT DatePart("yyyy",[ndate]);
My question is:
Is there anyway to write back the query result to table 1?
I want to add two new columns in table 1. And be able to add or update the query value to the field base on its "ID".
I'm not sure my description is clear or not. Hope you may understand and thanks for your help!
You won't be able to do it directly. However, here are two ways it could be done indirectly.
Method 1: Temp Table
This method is best for a quick-and-dirty one-time solution.
Create a Make-Table query based on your query and use it to make a temporary table.
Use the temporary table joined to [Table 1] to update your two new fields.
Delete the temporary table
Method 2: VBA Routine
This method is best when you want a repeatable method. It's overkill if you're only going to do it once. However, if you want calculated values for every year, you'll need to run it again.
Read the query into a recordset
Loop through the Recordset and for each ID, either
Run a sql statement to update table 1, or
open a second recordset querying by the ID and Edit/Update
Here's a simple version that updates the value for a single year.
Public Sub UpdateAnnualTotal(ByVal nYear As Long)
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim sSQL As String
Dim sId As String
Dim nTotal As Long
Set db = CurrentDb
sSQL = "SELECT [ID],[" & nYear & "_count"] FROM AnnualTotalsQuery"
Set rs = db.OpenRecordset(sSQL)
With rs
Do Until .EOF
sId = .Fields("ID").Value
nTotal = .Fields(nYear & "_count").Value
sSQL = "UPDATE [Table 1] SET [" & nYear & "_count"] = " & nTotal _
& " WHERE [ID] = '" & sId & "'"
db.Execute sSQL
.MoveNext
Loop
.Close
End With
End Sub

Using SQL in Query that auto updates

Thank you beforehand for your assistance. I know enough about Access, SQL, and VBA to get myself into trouble. Here is what I want to do.
I want to create a query that starts with a certain year and then lists each year up until the current year. The problem is that I want the query to automatically update as time progresses. In other words, say the start year is 2009, I want my query to list 2009, 2010, 2011, 2012, and 2013 since we are currently in the year 2013. Next year, the list will expand to include 2014. I suspect this is possible using a query in SQL but not sure how to go about coding it properly.
I bet that there is no simple solution for this simple process. We must use VBA to perform following steps:
Create a temporary table:
CREATE Table tblTmpYears (
ID COUNTER CONSTRAINT PrimaryKey PRIMARY KEY,
Year Long
);
In VBA:
Dim strSQL
strSQL = "CREATE Table tblTmpYears (" _
& " ID COUNTER CONSTRAINT PrimaryKey PRIMARY KEY," _
& " Year Long" _
& ");"
CurrentDb.Execute strSQL, dbFailOnError
Fill the temporary table:
INSERT INTO tblTmpYears (year) VALUES (2009);
INSERT INTO tblTmpYears (year) VALUES (2010);
INSERT INTO tblTmpYears (year) VALUES (2011);
INSERT INTO tblTmpYears (year) VALUES (2012);
INSERT INTO tblTmpYears (year) VALUES (2013);
In VBA, for 5 years, valid even after 100 years after our life existence:
Dim y as long, ymin, ymax, strSQL
ymax = Year(Date)
ymin = ymax - 4
For y = ymin to ymax
strSQL = "INSERT INTO tblTmpYears (Year) VALUES (" & y & ");"
CurrentDb.Execute strSQL, dbFailOnError
Next
Create a query for listing with the temporary table:
SELECT * FROM tblStudents INNER JOIN tblTmpYears
ON tblStudents.Year=tblTmpYears.Year
ORDER BY Year;
In VBA like this:
Dim qdf, strSQL
strSQL = "SELECT * FROM tblStudents INNER JOIN tblTmpYears" _
& " ON tblStudents.Year=tblTmpYears.Year" _
& " ORDER BY Year;"
Set qdf = CurrentDB.CreateQueryDef("qrySelTemporary", strSQL)
DoCmd.OpenQuery qdf.Name
Here you will have the Query Datasheet Windows with your students's list, it's printable. Even better, you can use it as
MyReport.RecordSource = "qrySelTemporary"
in an Access Report with a beautiful presentation.
Delete the temporary table after printing, for example:
DROP TABLE tblTmpYears;
In VBA:
Dim strSQL
strSQL = "DROP TABLE tblTmpYears;"
CurrentDb.Execute strSQL, dbFailOnError
Only VBA can accomplish this... rather than a single SQL query.
How about this - a small VBA function that outputs the SQL for an appropriate UNION query, which you can then assign as the RowSource for a combo box, use as a sub-query inside another dynamically generated query, or whatever:
Function CreateYearsToCurrentSQL(From As Integer) As String
Dim I As Integer, S As String
For I = From To Year(Date)
If I <> From Then S = S + "UNION "
S = S + "SELECT " & I & " AS Year FROM MSysObjects" + vbNewLine
Next I
CreateYearsToCurrentSQL = S
End Function
The FROM MSysObjects is because Access will whinge about no FROM clause if one isn't there, and MSysObjects is bound to be an existing table in an Access context (if you prefer though, replace it with the name of any other table).
So I managed to create a Query Criteria that does what I need.
Like (Right(Year(Now()),2)-3) & "-" Or Like (Right(Year(Now()),2)-2) & "-" Or Like (Right(Year(Now()),2)-1) & "-" Or Like Right(Year(Now()),2) & "-"
Thank you everyone for your efforts.

MS Access: How do I set up thie Recordset.Filter filter?

I have an issue that I am trying to find a solution for.
I have a table, it looks something like this:
#myTable
id - Number
value - Text
models - Memo
I also have a table that looks something like this:
#myModels
id - Number
model - Text
notes - Memo
The #myTable.models value is a concatenation of different #myModels.model strings concatenated with the '|' character. For instance, it might have ModelA|ModelB|ModelC| or only ModelA|ModelC|
I need to filter the recordset from #myTable based on which model is currently selected. Right now I have something like this:
Dim sql As String
sql = "SELECT * FROM myTable"
Dim rs1 As Recordset
Set rs1 = DBO.Edit (sql)
sql = "SELECT model FROM myModels"
dim rs2 As Recordset
Set rs2 = DBO.Read (sql)
If Not rs2.BOF Then rs2.MoveFirst
While Not rs2.EOF
If Not rs1.BOF Then rs1.MoveFirst
While Not rs1.EOF
Dim models() As String
models = Split(rs1![models], "|")
Dim model As String
For Each model In models
If model = rs2.model Then
'Do some processing
End If
Next model
rs1.MoveNext
Wend
rs2.MoveNext
Wend
I was really hoping that I would be able to perform some type of regex on the query or in the filter, so it would possibly look something like this:
While Not rs2.EOF
rs1.Filter( "Insert Regex Here" )
If Not rs1.BOF Then rs1.MoveFirst
While Not rs1.EOF
' Do Some Processing here
rs1.MoveNext
Wend
rs2.MoveNext
Wend
I guess that my main issue is that the #myModels table has ~ 1000 records and is growing, while the #myTable table has more than 30k records in it. This takes an extremely long time to loop through when trying to loop through each record that many times.
Any solutions would be greatly appreciated.
did you try sql = "SELECT model FROM myModels where criteria"?
not sure what you mean by currently selected model but you can use tempVars to add temporary strings or whatever else you need
perhaps join in your sql?
can you specify in detail where is this model coming from and how its selected
Iterating over records in VBA is generally slower than a single SQL query. Running through a single SQL query would be faster than multiple loops with VBA:
SELECT myTable.*
FROM myTable, myModels
WHERE myTable.models LIKE "%" & myModels.model & "%"
In VBA:
Dim sql As String, rs As Recordset
sql = _
"SELECT * " & _
"FROM myTable, myModels " & _
"WHERE myTable.models LIKE ""*"" & myModels.model & ""*"""
Set rs = dbs.OpenRecordset(sql)
While Not rs.EOF
'Some processing here
Loop
Admittedly, this will still be slow, because this is an outer join, and because we're using the non-optimized LIKE operator.
If instead of the myTable.models field, you can add an intermediate table:
#myTableModels
tableID - number
modelID - number
with proper relationships, the resulting query will be near-instantaneous:
SELECT myTable.*
FROM (myTable
INNER JOIN myTableModels
ON myTable.id = myTableModels.tableID)
INNER JOIN myModels
ON myTableModels.modelID = myModels.ID

Lookup and Display a Date Value from an Access Table

I am trying to have a msgbox popup when clicking on a command button within a form in Access 2003.
The msgbox should be triggered by the current date, when compared to dates referenced within a table that is in the database. It would look like this:
If Date() is < [Date in table?], THEN "Msgbox" = "It is now Quarter 2"
once it is beyond the date for quarter 3, the msg box would read "It is now Quarter 3"
Thanks if you can help
Access has a set of functions called Domain Functions for looking up a single piece of information stored in a table. Some of the most common ones are DCount(), DLookup(), DSum(), DAvg(), DMax(), and DMin().
You need to use the DLookup function for this. Basically, it needs a field name and a table name to lookup a value. And in many cases you want to include a criteria statement (or WHERE clause) as the third argument to make sure that the DLookup function is actually retrieving the value from the correct row. If you don't pass in a criteria statment, the Domain functions will simply return the first match.
If Date() <= DLookup("SomeDateField", "tblYourTableName") Then
MsgBox "The date in stored in the table is today or else is in the future."
Else
MsgBox "The date stored in the table is in the past."
End If
Here's an alternate way to write this:
If Date() < DLookup("SomeDateField", "tblYourTableName") Then
MsgBox "The date in stored in the table is in the future."
Else
MsgBox "The date stored in the table is today or is in the past."
End If
And here's how you do it if you have multiple records/rows in the table. You then need to some kind of criteria statement to narrow it down to retrieving the value you want to from the very row you want.
If Date() < DLookup("SomeDateField", "tblYourTableName", "UserID = 1") Then
MsgBox "The date in stored in the table is in the future."
Else
MsgBox "The date stored in the table is today or is in the past."
End If
While it's not really what you are asking, I think it's important to realize what's really going on behind the scenes with this function (and other domain functions). Basically, you are choosing to retrieve one single value from one single table with the option to specify which record/row you want the value retrieved from using a criteria statement, known as a WHERE clause in SQL. So let's take a look at how you would write a function like this, and at how Microsoft likely did write their DLookup function.
Public Function MyLookup(ByVal strField As String, _
ByVal strTable As String, _
Optional ByVal strCriteria As String) As Variant
'Error handling intentionally omitted
'Proper error handling is very critical in
'production code in a function such as this
If strField <> "" And strTable <> "" Then
Dim sSQL as string
sSQL = "SELECT TOP 1 " & strField & " FROM " & strTable
If strCriteria <> "" Then
sSQL = sSQL & " WHERE " & strCriteria
End If
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset(sSQL, dbOpenSnapshot)
If Not (rst.EOF and rst.BOF) Then
MyLookup = rst(strField).Value
End If
rst.Close
Set rst = Nothing
End If
End Function
Now let's suppose you want to find the birthdate of someone in your contacts table:
Dim dteBirthDate as Date
dteBirthDate = MyLookup("BirthDate", "tblContacts", "ContactID = " & 12345)
If you didn't have a DLookup function, (or if you didn't write your own), you'd end up writing all that code in the "MyLookup" function up above for every time you needed to lookup a single value in a table.
I think what you're looking for is the following:
'Dates to be retrieved from the db (quarter start dates)
Dim q1 As Date
Dim q2 As Date
Dim q3 As Date
Dim q4 As Date
'Today's date
Dim today As Date
Dim quarter As Integer
Set today = Date()
Set q1 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=1")
Set q2 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=2")
Set q3 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=3")
Set q4 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=4")
Set quarter = 1 'Base case.
If (today > q1) Then quarter = 2
If (today > q2) Then quarter = 3
If (today > q3) Then quarter = 4
MsgBox "It is quarter " & quarter 'Display which quarter it is in a msgbox
You may have to fiddle with the date formatting depending on how you have it stored in the database, etc. It would also be much more efficient to write it in another way (for instance remove the intermediary q# variables) but I wrote it out in a lengthy way to make it more clear.