Find value located in the last record using VBA - ms-access

I know this has probably been asked thousands of times before, but I seem to be having trouble finding an existing question that addresses this question in a wy I can understand.
My question in how can I access a value located in the last record of a table? For example, if this is my table:
personID personName personNumber
1 Sally PR32
2 Emily PR33
3 Joseph PR34
I want to access the value "PR34" (and then be able to manipulate it if possible). I know how to find the last record with Dmax, but I'm struggling to figure out how to find a value within it. I'm ultimately trying to take the value, parse the string down to just the numbers, and increment it by one (and then append the letters back on).

You can do this in a query as well:
UPDATE T
SET T.personNumber = "PR" & CLng(Replace([personNumber], "PR", "")) + 1
WHERE (((T.personID)=(SELECT Max(personID) FROM T)));
Where T is the name of your Table.

If you're in the DLookUp/DMax workflow, you can just use the following:
This gives you the ID, you already figured this out:
DMax("PersonID", "MyTable")
Then lookup the associated personNumber with that ID:
DLookUp("personNumber", "MyTable", "personID = " & DMax("PersonID", "MyTable"))
But if you want to manipulate it (or just be more efficient), using a recordset is the way to go:
'Create a recordset
Dim rs As Recordset
'Query the last value, get the personNumber
Set rs = CurrentDb.OpenRecordset("SELECT TOP 1 personNumber FROM MyTable ORDER BY personID DESC")
'Open it up for editing
rs.Edit
'Increment the number by 1
rs.Fields("personNumber").Value = Left(rs.Fields("personNumber").Value, 2) & CInt(Mid(rs.Fields("personNumber").Value, 3, Len(rs.Fields("personNumber").Value) - 2)) + 1
'Update the recordset
rs.Update

Related

Find Value in Last Instance of Multiple Record

I'm new to Access and SQL so I'm having a bit of trouble with this undoubtedly simple issue.
I'm using VBA and SQL to update a table based on a few listbox selections.
One of the fields I'm updating is an "instance" field which tracks the instance number of each ID. For example, the first time ID 5 was added to the table its instance number would be 1. The second time it was added to the table its instance would be 2. So it would look like this:
ID | Date | InstanceNUM |
005 | 11/22/2013 | 1 |
005 | 11/23/2013 | 2 |
and so on. It's likely that other records would/will separate the two records in the example above.
After doing some research, it seems like DLast is the best function for this job since the last instance of the particular ID will also contain the instance number in field three. However, when I use this syntax:
Dim i As Long
Dim IDnum As Long
i = DLast("[InstanceNum]", "tbl_Data", [ID] = IDnum)
'where [InstanceNum] is the field name for the value I want to return, _
'"tbl_Data" is the table name where the value I want to return exists, _
'and [ID] is the field name where the ID exists.
I get the Run-time error '94': Invalid use of Null. My understanding of this error is that DLast couldn't find a value based on this criteria (and it can't store that result in a Long data type variable), but I know that the record exists (I've checked the table for the value and I've checked the variable for the value).
EDIT
The [ID] field is a text data type. I set the IDnum variable this way:
Dim IDnum As String
Set ctlList = Me!List7
For i = 0 To ctlList.ListCount - 1
If ctlList.Selected(i) = True Then
IDnum = ctlList.Column(0, i)
Exit For
End If
Next I
The above code loops through a listbox in a form I have and sets the IDnum variable as the ID number in the first column.
Per HansUp's suggestion, I have updated my code to this:
i = DLast("InstanceNum", "tbl_Data", "[ID] =" & IDnum)
But now I get the Run-time error '3464': Data type mismatch in criteria expression.
I'm at a loss for why this is happening. Perhaps there's an easy answer to this, but I haven't been able to find one... And maybe there's an easier way to do this? Does anyone know why this error is happening?
Since [ID] is text type, add quotes around the value of IDnum for DLast.
i = DLast("InstanceNum", "tbl_Data", "[ID] = '" & IDnum & "'")
However if the stored [ID] values include leading zeros, you must Format IDnum to include those.
i = DLast("InstanceNum", "tbl_Data", "[ID] = '" & Format(IDnum, "000") & "'")

How to do an update query using a specific record from another table in Access?

I'm using Access 2010 and I want to know how to update a record from one table with the information from another table (but also, I want to specify which record from that other table I want to use). I have two tables (Products and Sales). What I need to do is that when I register a new sale on the Sales Form (specifying the units sold), I want to discount the units sold from the available units of that product in the Products table. I read that I need to use an Update Query, and do something like this:
Field: Available units
Table: Products
Update to: [Products].[Available units] - [Sales].[Sold units]
Field: Code
Table: Products
Update to:
Criteria: [Insert code]
The two tables are related by the Code field, being Code the primary key field from the products table (the products are registered only once) and the primary key field from the sales table is a auto-numbered field called SaleNumber. There can be many sales for one product.
I hope you can help me, I can't find anything. I'm kind of new in Access.
If you're using a form and want to write a bit of VBA, you can create a submit button that runs everything you need. It could look something like this:
Private Sub Submit_Button_Click()
Dim myR as Recordset
Dim myR2 as Recordset
Dim strSQL as String
'Select the product from the table that contains the available products
strSQL = "SELECT * FROM Available_Units WHERE Products = '" & me.product_field & "'"
'Set each table accordingly
Set myR as CurrentDb.OpenRecordset(strSQL, dbOpenDyanset)
Set myR2 as CurrentDb.OpenRecordset("Sold_Units_Table", dbOpenDynaset)
'This will edit the existing amount you have in the first table
myR.Edit
myR![Product_Qty] = myR![Product_Qty] - me.qty_sold
myR.Update
'This will add a new record of the transaction in the second table
myR2.addnew
myR2![Product_Sold] = me.product_field
myR2![Product_Qty_Sold] = me.qty_sold
myR2.Update
Set myR = Nothing
Set myR2 = Nothing
End Sub
Hopefully this will help a bit if you wanted to go the VBA route.

How to group records in date ranges based on a certain field

I am currently using a continuous form to a show a set of data that results in the following format (each line being one record):
1/04/13 Person1
31/03/13 Person1
30/03/13 Person1
29/03/13 Person2
28/03/13 Person1
There are 100s of these records and I would like to condense it to the following:
30/03/13 - 1/04/13 Person1
29/03/13 Person2
28/03/13 Person1
The data is from a query, so can be manipulated at the SQL level before it even gets to the form stage. I am also comfortable using macros or VBA to manipulate the form. However, I still haven't been able to find a suitable way of doing this.
I realise that this is typical behaviour for a report, but since I eventually want this to be embedded in another form as a subform, I can't use reports (can't create a subreport in a form unless I am missing something).
Any help or advice is much appreciated.
Good description of the problem. Try building your source query like this (assuming the fields are called MyDate and MyPerson and the source table is MyTable):
Select Person, min(MyDate) as StartDate, max(MyDate) as EndDate
from MyTable
group by Person
This gives you 3 fields that you can drop into your form.
Edit
Now that we have a more complete picture, the task just got more complicated, but you still have options assuming the 'events' between people don't overlap (if they do, then I can't think of how to create eventIDs afterward). In the absence of an EventID, you'll have to create one:
First, you need to move your data to a new table so that you can reorder it and add a blank field for the event ID you'll be adding in step 2.
1a. Copy MyTable into a new table. Add an extra field called EventID.
1b. To populate this table, first Delete * from TmpTbl
1c. Then something like:
Insert into TmpTbl.* from MyTable order by MyDate,MyPerson
This code will look through your temp table (TmpTbl as i call it) and add an event id.
Sub AddEventIDs()
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset("TmpTbl")
Dim LastPerson As String
Dim EventID As Integer
docmd.setwarnings false
While rst.EOF = False
If LastPerson <> rst.Fields("MyPerson") Then EventID = EventID + 1
LastPerson = rst.Fields("MyPerson")
rst.Edit
rst.Fields("EventID") = EventID
rst.Update
rst.MoveNext
Wend
docmd.setwarnings true
End Sub
On the On Load event of your form, add in the 2 queries and the sub routine from #1 and #2.
Your final query will be:
Select MyPerson, EventID, min(MyDate) as StartDate, max(MyDate) as EndDate
from MyTable
group by MyPerson,EventID

manipulate query result to create another table

OK so I have tried a few differrent ways and searched the forums. I've found similar problems to the one I'm having, but not quite what I'm looking for.
I have a query on my database that returns 2 columns. In the first column is a code number, and the revision for the code number in the second
e.g.
Code_1 0
Code_1 1
Code_2 0
Code_2 1
Code_2 2
Now what I need to do is loop through this query and pick out the code and the maximum revision number associated with each code number and put these into another table so I would end up with
Code_1 1
Code_2 2
in my new table.
I've can't even seem to loop through the query and all I get each time is the first result. I've used Debug.Print below to show myself exactly what my loop is doing.I've done some Java and the vba loops are obv different. One way I've tried is:
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("Query_Name")
Dim i,j as Integer
Dim tempvar1, tempvar2 As Variant
For i = 0 To rs.EOF
tempvar1 = rs!Code_Number
For j = 0 to rs.EOF
tempvar2 = rs!Code_Rev
If Code_Rev > tempvar2 Then
tempvar2 = rs!Code_Rev
End If
Debug.Print(tempvar1 + tempvar2)
Next j
Next i
All I get is the first code number and revision on the list. If I can't even loop through the list properly I've no hope of creating a new table from the results I need :-/
I've also tried doing something similar with a Do While Loop but same type of result.
Please show me the error of my ways in iterating through the query and please help me create a new table from the results.
Why not a straight query?
SELECT tx.Code, Max(tx.[NewCode]) AS MaxOfC INTO New
FROM tx
GROUP BY tx.Code;
Where tx is the name of your table.

How can I count all the NULL values in all columns in an Access 2010 table?

I need to be able to count all the NULLS in all columns of an Access 2010 table. what I mean by that specifically, is that of the 30 columns (fields) there are loads of records with partial data.
I want to count in the entire table how many are empty.
I read the article on this site titled, How to count all NULL values in table, but that referred to SQL and also, was, I am sorry to admit too complex for me.
Anyone got any futher clues?
:)
For a single field, you could use a simple query.
SELECT Count(*) AS CountOfNulls
FROM MyTable
WHERE some_field Is Null;
If you want to count Nulls separately for multiple fields in a single query, you can do something like this:
SELECT
Sum(IIf(some_field Is Null, 1, 0)) AS NullsIn_some_field,
Sum(IIf(another_field Is Null, 1, 0)) AS NullsIn_another_field
FROM MyTable;
If you want a grand total of all Nulls, instead of a count per column, you can use the previous query as a subquery and add up the individual column counts.
SELECT base.NullsIn_some_field + base.NullsIn_another_field AS total_nulls
FROM
(
SELECT
Sum(IIf(some_field Is Null, 1, 0)) AS NullsIn_some_field,
Sum(IIf(another_field Is Null, 1, 0)) AS NullsIn_another_field
FROM MyTable
) AS base;
OTOH, if you prefer to avoid SQL altogether, or simply find those statements too complex, you don't need to use SQL. You could use the DCount() function in a VBA procedure.
Run the procedure below in the Immediate window with the name of a table in your database:
HowManyNulls "YourTable"
You can go to the Immediate window with the CTRL+g keyboard shortcut.
Public Sub HowManyNulls(ByVal pTable As String)
Dim db As DAO.Database
Dim fld As DAO.Field
Dim tdf As DAO.TableDef
Dim lngNulls As Long
Dim lngTotal As Long
Set db = CurrentDb
Set tdf = db.TableDefs(pTable)
For Each fld In tdf.Fields
'lngNulls = DCount("*", pTable, fld.Name & " Is Null")
' accommodate field names which need bracketing ...
lngNulls = DCount("*", pTable, "[" & fld.Name & "] Is Null")
lngTotal = lngTotal + lngNulls
Debug.Print fld.Name, lngNulls
Next fld
Debug.Print "Grand total", lngTotal
Set fld = Nothing
Set tdf = Nothing
Set db = Nothing
End Sub
If none of these suggestions is satisfactory, please revise your question to help us better understand what you need.
There is no easy way to perform this kind of count across "all columns" of a table when you do not know the column names in advance.
If you want to do so, you have to write a program to read the "metadata" of the database, extract a list of columns and tables from that data, for each column build a separate SQL statement, then execute that statement and add the number you get back to a running total of NULL values found.
Does this sound like something you might consider pursuing? If so, you should search for solutions on getting the list of tables in an MS Access database and getting the list of columns for a table in an Access database, and then combine that information with the information you already have from the question about counting NULLs in a column.
To count null values in a table of all columns:
select count(*) from(select a from tt where a is null
union all
select b from tt where b is null
union all
select c from tt where c is null)