How to get the formatted autonumber value in MS Access to appear in form control as a formatted value? - ms-access

I have an ID field with an AutoNumber Data Type that has a custom format defined in the Field Properties (A-00001, A-00002, etc).
I wanted to look up the formatted value and display it in a form textbox control.
ServiceNumber_entry = DLookup("ServiceID", "ServiceRecord", "SNID = '" & Forms!ServiceEntry!PartSN_entry & "'")
Using the line above, it returns just the number value and not the full formatted value (i.e. 1 instead of A-00001). What am I missing?

Existing comments all contain good information, but it can be useful to put it all together. The comments also failed to describe the context in which Access automatically copies and applies properties like Format, so that the comments (even if correct) might seem contradictory. My explanation is a bit verbose, but hopefully avoids further confusion.
The purpose of the Format property for any value in Access is to define how the data is displayed. This is true of a table column presented in a datasheet or a textbox control on a form. The Format does not define how values are stored, either in storage or in memory. The same value could be formatted and displayed differently without affecting the underlying stored datum. In this case, the Autonumber values are really Long Integer values. (They are not stored with a preceding "A-", which would require the values to be strings and would ruin Access's ability to automatically increment the values.)
Access attempts to provide a consistent view of the data and reduce tedious programming details by automatically copying the Format property to queries and form controls, just as it does with many other metadata properties. For instance, if you drag the AutoNumber field onto a form in design mode, it will automatically copy the Format string from the column to the TextBox control's Format property. In contrast, if you include the same column in a query, the query's column property sheet also has a Format property, but it will remain blank by default. However, when the query is executed, it will indeed be displayed with the format defined on the table column. This behavior does not mean that the data values themselves "have a format", rather Access is just doing its automatic work of looking up default formatting values from the table definition and applying it to the query's output. (It can do this if there is a simple one-to-one table column to query column relation, which is the usual case for queries.)
DLookup() is a Visual Basic (VBA) function. It is necessary that such functions handle the "raw" data independently of metadata, like Format (or Caption, Text Alignment, etc.). For coding purposes, a programmer expects to retrieve the actual long integer value from the column, not a formatted string value like "A-00001". The function will not only skip the format, the formatting information is completely dropped from data values. In a programming environment, data can be combined and manipulated and the concept of "format" becomes lost and/or meaningless. Even though in this case it might seem obvious, DLookup makes no assumptions about what you're going to do with the data and so just returns the integer values.
If your form TextBox control was not originally placed on the form specifically for the AutoNumber field, Access would not know to the copy the Format property. It would just display the integers from DLookup() as basic integers. However, you can manually set the TextBox's Format property to match the table column's Format property exactly to get back the expected values.

Related

Format a column with percentage using VBA

I am exporting a report to Excel from Access through VBA. There is a column in the report that should be formatted as percentage and round. How can I format this?
Set the Format property of the textbox in the report to: Percent
You may have to divide the value by 100 first. If so, rename the textbox to anything else than the name of the field, and use this expression as ControlSource:
=[YourFieldName]/100
For a new formatted string value, use Format:
=Format([YourFieldName],"Percent")
You don't mention what kind of rounding you need, but functions for all general methods of rounding are listed here: Rounding values up, down, by 4/5, or to significant figures

Using an expression in a numeric form control

I have an Access form with a textbox bound to a currency field in a table. As expected, anything other than a numerical entry generates an error. Occasionally, users need to enter several amounts and have those added together and the result entered into the currency field.
To accomplish this, I would like users to enter an equal sign followed by a valid arithmetical string which would evaluate to a number exactly as they would in an Excel cell. For example, if a user enters "=5.31+2" I want the field to evaluate to "7.31" and use that as the value passed to the table when the record is updated or saved. The current workaround is to use the Calculator application but that isn't the ideal solution.
I tried the following code and applied it to both the BeforeUpdate and OnLostFocus events of the textbox (named "tbxTotal_Paid") but neither worked. I simply got "The value you entered is not valid for this field" error.
Dim charCt As Integer
Dim evalStr As String
If Left(tbxTotal_Paid, 1) = "=" Then
charCt = Len(tbxTotal_Paid)
evalStr = Right(tbxTotal_Paid, charCt - 1)
Me.tbxTotal_Paid = CCur(evalStr)
End If
Is this simply applying the code to the incorrect event or is this a coding issue? Any assistance is appreciated.
For me your code looks fine but you might put it in the wrong place.
Like you said Acess is giving you this error because the textbox is bound to the currency-field. So it will never accept non-numerical values because the value-checking code fires even before the before_update-event.
I think the best solution would be to hide your bound text box using Me.tbxTotal_Paid.Visible = False and creating a surrogate textbox which is not bound. You put your code in the beforeUpdate-Event or Change-Event of your surrogate. At the end you should check your final result with IsNumeric(). That way your surrogate textbox writes only correct values to your bound hidden textbox and only numbers arrive at your table.
An alternative would be to change the currency column to a string-field but this would not be wise because of potential wrong data in your database.

Input mask in Access database

I have a field with a customer ID that should be in the format of C0000000001, where it has a letter at the start and up to 10 numbers after the letter with leading zeros between the letter and the number. I want the users to be able to put in C1 and have the table save C0000000001 or C1234 and have the table save C0000001234.
I want the restriction to be on the hard data in the table. The table should contain the full customer ID but I only want the users to have to enter the C and the number of the customer when entering/searching for customers. I am using Access 2010.
I believe that the first character will always be a C, but either way, it would only be one alpha character if it wasn't.
I understand what you are saying, but the majority of the data (thousands of records) are going to be from another system that stores them that way. Doing it this way limits my margin of error. Otherwise, exports from the other system will need to be manually changed prior to being imported into the database and vice versa.
Searching would only be on existing records that will be saved in the C0000001234 format, but I would like user to be able to omit the leading zeros when entering the search criteria.
This question, combined with your previous question here, suggest to me that you are trying very hard to have the data structure in your Access database exactly match the legacy system from which you receive bulk updates. That may not be necessary, or even desirable.
For example, instead of maintaining the CustomerId as Text(11) (as in the old system) you could store it in your Access database as
CustomerIdPrefix: Text(1), and
CustomerIdNumber: Long Integer or perhaps Decimal if the numeric part really can exceed 2,147,483,647
Your Customers table in Access could also include a calculated field named CustomerId as
[CustomerIdPrefix] & Right("0000000000" & [CustomerIdNumber], 10)
to give you a single 'C0000012345' value for display purposes.
For searching, your form could have a Text Box for the Prefix (default value: 'C') and another text box for the numeric part. The search could then use a condition like
[CustomerIdPrefix] = txtPrefix.Value AND [CustomerIdNumber] = txtNumber.Value
or, if the user wanted to create a Filter on the Form (or Datasheet View) it would probably be sufficient to just filter on the number part.
If you ever needed to feed information back to the legacy system you could just export a query that includes the [CustomerId] calculated field (and omits [CustomerIdPrefix] and [CustomerIdNumber]) and you'd be fine.
My suggestion would be to use forms with associated queries using the FORMAT function.
You do need to clarify where you want this implemented, but I'm going to assume you have a table set up and that you would like to be able to enter/search data from a form.
I'll create one form for input frmAdd. For the input form, I created a query that would run when a button on the form was pressed. Add two text boxes newID and newOther to the forms which are unbounded but which the user can use to enter data. The query will then pull that data and append it to your table in an altered format. Here's the SQL for that query:
INSERT INTO Customers ( [Customer ID], [Other Field] )
SELECT Left([Forms]![frmAdd]![newID].[value],1)
& Format(Right([Forms]![frmAdd]![newID].[value],Len([Forms]![frmAdd]![newID].[value])-1),"0000000000")
AS Expr1, Forms![frmAdd]!newOther AS Expr2
FROM Customers;
I'm not sure exactly what search functionality you're looking for, but this query would pull up the record data matching that of a frmSearch with a textbox search which would have the format C### or whatever entered in:
SELECT Left([Customers].[Customer ID],1) & Replace(LTrim(Replace(Right([Customers].[Customer ID],9),'0',' ')),' ','0')
AS Expr1, Customers.[Other Field]
FROM Customers
WHERE (((Customers.[Customer ID])=Left([Forms]![frmSearch]![search].[value],1)
& Format(Right([Forms]![frmSearch]![search].[value],Len([Forms]![frmSearch]![search].[value])-1),"0000000000")));
Applying the input mask is just a way to ensure that your data is correct. If you feel the need to use one, go to the table in Design View and click on the Data Type box for the customer ID field. Find Input Mask under Field Properties -> General and click it. Then hit go to the toolbar -> Design tab -> Builder. This will walk you through it.
Input mask is not the answer for this. Input mask forces the user to input the data in a certain manner. What you need is some VBA code to run in the AfterUpdate event on a form. There's no way within the table to force the data into this pattern allowing the input method that you've requested.
There may be a more efficient way to do this, but this does the job.
http://pineboxsolutions.com/access/customeriddemo.accdb

MSAccess Change Date Value Before Validation

In a grid I have a date/time field where I would like the user to be able to type in short-hand formats for dates and times. For example, if they type in "435p" and then focus off of the cell they get the message "The value you entered isn't valid for this field.". Instead, I want to trap a pre-validationevent and change it to "4:35pm" for them.
What event can I use?
I've tried:
LostFocus & BeforeUpdate: too late (validation fires before event)
Dirty & OnChange: too early (they haven't left the cell yet)
Or is there a way to turn off the native validation rule that is checking for date formats?
You could use an additional text field without formatting (or with your very own format). Then show this instead of the datetime-field and update the date-time field with your code.
Not very pretty, but if you always format the input to a proper time string on before-update and never access this field (but rather the real date-time field) you should be ok. You could even name the field Helper_DateTime or somesuch, so you are never tempted to access the field from anywhere else ;)

MS Access setting to ignore date conversion error

An Access DB imports a fixed width text file; one column is mostly dates.
When the date is not available, the file's creator actually uses the string "Null"
Access puts the row in the table with that field actually null.
But, when the files started coming with different field widths, I copied the DB, tweaked the starting/width values in the input spec, and imported. NOW, all the rows with null get logging in (table)_import_errors as an error converting text to date.
I have found no setting (not that I changed any) to explain it. One difference is that although both DBs are in Access 2000 format, the original is on a machine that still has Access 2000, while the new one is being handled by Access 2003.
Is that a behavior change in the Access version? Is pre-processing the file the only solution?
Thanks, David. That's what I would have done (except for the Excel part) if it had not fixed itself. I posted that, but apparently someone didn't like the public admission that Access has bugs.
The only thing that changed was that two other columns in the fixed width plain text input was wider. Yet Access "decided" to discard the whole row instead of just the date field for three consecutive attempts. The fourth time, it still reported it as an error but imported the rest of the row.
So, when Access misbehaves for no good reason, try again a time or two, then try explicitly coding the conversion from text.
Two possibilities:
Use a buffer field or buffer table that imports the date field into a text field. Then you can process that into the appropriate values in the final destination field.
Use a SQL import instead of DoCmd.TransferText. What you do in that case is use a connect string in the FROM clause so you can then process the date field in your SELECT:
SELECT Sheet1.FirstField, Replace(Sheet2.DateField, "NULL", Null) As DateField
FROM Sheet1 IN 'C:\Import\Spreadsheet.xls'[Excel 5.0;HDR=YES;IMEX=1;];
Convert that into an INSERT query and you're golden.