I have a pivot query I need to loop through and add to another temporary table. The pivot query is a sum of the different statuses found. The statuses are Early, Late, and On-Time. Based on what the user selects, not all of the statuses are present. So when I run the following:
Set rs1 = CurrentDb.OpenRecordset("MyReceivingOnTimeDeliverySummary", dbOpenDynaset)
Set rs = CurrentDb.OpenRecordset("TRANSFORM Sum(recvqty) AS SumOfrecvqty " & _
"SELECT supname, Sum(recvqty) AS TotalReceivedQty " & _
"FROM MyReceivingOnTimeDeliveryDetail " & _
"GROUP BY supname " & _
"PIVOT Status", dbOpenDynaset)
If (rs.RecordCount <> 0) Then
rs.MoveFirst
Do While rs.EOF <> True
rs1.AddNew
rs1.Fields("[supname]").value = rs.Fields("[supname]").value
rs1.Fields("[TotalReceivedQty]").value = rs.Fields("[TotalReceivedQty]").value
rs1.Fields("[Early]").value = rs.Fields("[Early]").value
rs1.Fields("[Late]").value = rs.Fields("[Late]").value
rs1.Fields("[OnTime]").value = rs.Fields("[On-Time]").value
rs1.Update
rs.MoveNext
Loop
End If
If one of the statuses isn't in the results of the query then I will get an error where I am adding that value to the MyReceivingOnTimeDeliverySummary table.
How do I test to for each status and if they are not there then add as 0?
You should be avoiding recordsets for simple operations, like copying with small, uniform changes, in this case. But good news: this makes everything easier!
First, use the SQL statement you already have to create a query.
Dim db As Database
Set db= CurrentDb
db.CreateQueryDef "qry1", "sqltext"
Then, from that query, SELECT INTO (or INSERT INTO) your summary table.
db.Execute "SELECT * INTO MyReceivingOnTimeDeliverySummary FROM qry1"
Then you can add the fields if they aren't there.
On Error Resume Next: db.Execute "ALTER TABLE MyReceivingOnTimeDeliverySummary ADD COLUMN Early NUMBER": Err.Clear: On Error GoTo 0
On Error Resume Next: db.Execute "ALTER TABLE MyReceivingOnTimeDeliverySummary ADD COLUMN Late NUMBER": Err.Clear: On Error GoTo 0
On Error Resume Next: db.Execute "ALTER TABLE MyReceivingOnTimeDeliverySummary ADD COLUMN OnTime NUMBER": Err.Clear: On Error GoTo 0
Finally, fix the nulls to zero.
db.Execute "UPDATE [MyReceivingOnTimeDeliverySummary] SET [Early] = Nz([Early],0)"
db.Execute "UPDATE [MyReceivingOnTimeDeliverySummary] SET [Late] = Nz([Late],0)"
db.Execute "UPDATE [MyReceivingOnTimeDeliverySummary] SET [OnTime] = Nz([OnTime],0)"
Why do it this way? In my experience, SQL is a lot faster than recordsets.
Set the default value to zero for any of the MyReceivingOnTimeDeliverySummary fields which may not be present in the pivot query.
Then loop through the fields in the pivot query recordset and add those fields' values to the matching fields in the other recordset.
Dim fld As DAO.Field
If Not (rs.BOF And rs.EOF) Then
rs.MoveFirst
Do While Not rs.EOF
rs1.AddNew
For Each fld In rs.Fields
rs1.Fields(fld.Name).value = rs.Fields(fld.Name).value
Next
rs1.Update
rs.MoveNext
Loop
End If
Incidentally, you may also find the code operates faster if you substitute dbAppendOnly for dbOpenDynaset here:
OpenRecordset("MyReceivingOnTimeDeliverySummary", dbOpenDynaset)
I'm unsure how much of an impact that change will have. It doesn't change the logic of what you're trying to accomplish. And perhaps any speed impact would be insignificant. But it won't cost you much to find out. :-)
Related
I have two tables that I wish to compare records - based on a field values. Here is what I tried :
Dim RCount As Long
Dim Rst As Recordset
Dim Rst1 As Recordset
Dim f As Field
'Current Record set
Set Rst = CurrentDb.OpenRecordset("Table1")
Set Rst1 = CurrentDb.OpenRecordset("Table2")
With Rst
For Each f In Rst1.Fields
RCount = DCount("FieldFromTable1", "Table1", "[FieldFromTable1]='" & Me.[FieldFromTable2].Value & "'")
If RCount > 0 Then
Me.Checkbox1.Value = True
End If
Next f
End With
Rst.Close
Rst1.Close
Here is my updated question, something like that I'm trying to accomplish. But still this code cycles only through currently selected record in my Table2 form.
Following on from my comment. You can use recordcounts to see if there is a record that exists and matches. You could use the following query to see if a record exists:
dim rst as recordset
dim varSQL as string
varSQL = "SELECT [fieldfromtable1] FROM Table1 WHERE [fieldfromtable1] ='" & [fieldfromtable2].value & "'"
Set Rst = CurrentDb.OpenRecordset(varSQL)
If rst.recordcount = 1 then
MsgBox "Fields have matching values !"
End If
rst.close
You could replace the =1 with >0.
Alternatively, I think you can use dcount() function which would be something like:
dim RCount as long
Rcount = dcount("fieldFromTable1","table1", "[fieldFromTable1]='" & me.[FieldFromTable2].value & "'")
if Rcount > 0 then
MsgBox "Fields have matching values !"
end if
again, you can use >0 or =1 im not sure which is most appropriate for your situation.
Edit
the following query can be performed to update the checkbox, but this isn't at form level
UPDATE table1 INNER JOIN table2 ON table1.[fieldfromtable1] = table2.[fieldfromtable2] SET table1.[checkboxField] = True
WHERE table2.[fieldfromtable2]= table1.[fieldFromtable1]
I haven't really consider an option to just UPDATE records in tables. Thsi is what It worked for me. I was just trying to set Checkbox to TRUE when record from Table1 meets criteria in Table2. A simple UPDATE solved the problem:
Dim SQL As String
niz = " UPDATE Table2" & _
" INNER JOIN Table1" & _
" ON Table1.FieldFromTable1=Table2.FieldFromTable2" & _
" SET Table2.Checkbox1=True"
DoCmd.SetWarnings False
DoCmd.RunSQL niz
DoCmd.Requery
DoCmd.SetWarnings True
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
In a Access 2003 database, I have an "Inscriptions" (subscription) database with a primary key on 2 fields idPersonnel (employee) and idSession.
I have made a form so that user can select a session (in a listbox), then one or more employee (another listbox) and suscribe them to that session by using a button, which, on VBA side, first check that there is enough room on the session (defined by "MaxParticipants" field on "Sessions" table, linked to "Inscriptions" table on idSession), then insert data in "Inscriptions" table
This is working fine in a single-user environnement, but fails if 2 people want to join some employees on the same session at the same time, as I have a confirmation message between check and insertion. Therefore 2 users can select employees, get the confirmation message (at this point both are told there is enough room), resulting in having more people than expected joined to the session.
Fortuneatly, if both users try to insert the same employee(s) to that table, one will get a duplicate error, but insertion will be made if employees are different.
On another DB engine, such as SQL server, I would use a stored procedure that would lock the table, do the check and the insertion then unlock the table.
But it does not seem to be possible in MS Access.
What are the possibilities in MS Access to prevent a session from having more than maximum number of participants ? Any help is appreciated.
One way to accomplish your goal would be to do the INSERT in a transaction, count the participants for that session, and roll back the transaction if the new total exceeds the limit:
Option Compare Database
Option Explicit
Sub AddParticipant()
Dim cdb As DAO.Database, cws As DAO.Workspace, _
qdf As DAO.QueryDef, rst As DAO.Recordset
' test data
Const idPersonnelToAdd = 4
Const idSessionToAdd = 2
Set cdb = CurrentDb
Set cws = DBEngine.Workspaces(0)
cws.BeginTrans
Set qdf = cdb.CreateQueryDef("", _
"PARAMETERS prmIdPersonnel Long, prmIdSession Long; " & _
"INSERT INTO Inscriptions (idPersonnel, idSession) " & _
"VALUES (prmIdPersonnel, prmIdSession)")
qdf!prmIdPersonnel = idPersonnelToAdd
qdf!prmIdSession = idSessionToAdd
qdf.Execute dbFailOnError
Set qdf = Nothing
Set qdf = cdb.CreateQueryDef("", _
"PARAMETERS prmIdSession Long; " & _
"SELECT " & _
"Count(*) AS NumParticipants, " & _
"First(MaxParticipants) AS Limit " & _
"FROM Inscriptions INNER JOIN Sessions " & _
"ON Inscriptions.idSession = Sessions.idSession " & _
"WHERE Sessions.idSession = prmIdSession")
qdf!prmIdSession = idSessionToAdd
Set rst = qdf.OpenRecordset(dbOpenSnapshot)
If rst!NumParticipants <= rst!Limit Then
cws.CommitTrans
Debug.Print "INSERT committed"
Else
cws.Rollback
Debug.Print "INSERT rolled back"
End If
rst.Close
Set rst = Nothing
Set qdf = Nothing
Set cws = Nothing
Set cdb = Nothing
End Sub
I have a table that needs to be filled with some record through a form. I am using this code:
Set rp = CurrentDb.OpenRecordset("table1")
Do
rp.Edit
rp!field2 = Text22
rp.Update
rp.MoveNext
Loop
When the code fills the table and gets to the end of the file, I get the 3021 error.
Why is this happening?
Try this one:
Set rp = CurrentDb.OpenRecordset("table1")
Do Until rp.EOF
rp.Edit
rp!Field2 = Text22
rp.Update
rp.MoveNext
Loop
another way would be to use something like this:
CurrentDb.Execute "UPDATE table1 SET field2='" & Text22 & "'", dbFailOnError
It would be much, much quicker to use SQL if you wish to update every row in a table to a specific value.
For example:
sSQL= "UPDATE Table1 SET Field2=param"
Set qdf = db.CreateQueryDef("", sSQL)
qdf.Parameters!param = Trim(Me.Text22)
qdf.ReturnsRecords = False
qdf.Execute dbFailOnError
intResult = qdf.RecordsAffected
MsgBox "You updated " & intResult & " records."
You can even specify the type of parameter, for example:
sSQL= "PARAMETERS param Text(150); UPDATE Table1 SET Field2=param"
It is far safer to use parameters that to build sql strings.
I try to write a query in my Access Project but this runtime error occures in the line, where SQL query is. This is my code:
Private Sub Befehl80_Click()
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("SELECT DISTINCT tb_KonzeptDaten.DFCC, tb_KonzeptDaten.OBD_Code AS Konzept_Obd,tb_KonzeptDaten.DFC INTO Test_Table FROM tb_KonzeptDaten", dbOpenDynaset)
Me.txtDs = rst.RecordCount
End Sub
Would you please tell me how can I solve this problem and why this error occures?
The sql is an action query, it creates a table. You cannot open a recordset from an action query. If you want to run the action query, you can say:
Set db=CurrentDB
ssql="SELECT DISTINCT tb_KonzeptDaten.DFCC, " _
& "tb_KonzeptDaten.OBD_Code AS Konzept_Obd,tb_KonzeptDaten.DFC " _
& "INTO Test_Table FROM tb_KonzeptDaten"
db.Execute ssql, dbFailOnerror
RecordsUpdated=db.RecordsAffected