I have a combo box with a RowSource. When it displays, it shows a list of items that come from a query. The query has two columns. When the user chooses something, the first column is stored in the table, but the second column is displayed (works fine).
When you come to the form and view some existing data, it shows the display value from the query (RowSource) like it should. Works nice most of the time.
The challenge is that one of my combo boxes deals with case-sensitive keys. The wrong stuff is getting shown.
Here is some contrived data:
id value
[a1] [Apples]
[A1] [Oranges]
The underling table is like this:
MyTable
id: int
...other fields...
fruit_key: string
When the fruit_key column contains, "a1", I want to see Apples. When it contains "A1", I want to see Oranges.
What's happening is that I am always seeing Apples because it's doing a case-insensitive match.
How do I change this to case-sensitive?
You can't, except with kludgy workarounds. From How To Perform a Case-Sensitive JOIN Through Microsoft Jet:
The Microsoft Jet database engine is inherently case-insensitive.
And there is no way to change that.
In WHERE conditions and JOINs in queries, you can work with binary string compare: StrComp(Field1, Field2, 0) = 0.
But here, with the bound combobox, your best choice would be to convert the fruit_key string into e.g. a hex string (see Hexadecimal Expansion in the article).
In the rowsource of the combobox you could use a computed column, but in the table you want to edit with the combobox, you'd have to actually store the hex string in addition to the fruit_key, because you can't edit a computed column.
I'm not sure if or how the Binary Field method would work in your case.
All in all you'd probably be better off by
"doing it differently" so that you don't need the case-sensitive data, or
not using Jet as backend, but a server database, where you can set a case-sensitive collation.
Related
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.
I'm trying to make a MS Access report, where I use a text box to display a field value, then have another text box indicating if the first value is higher or lower than an entry in a separate table.
The report has a record source of "Table 1", and a textbox named "txt_Value1" which displays the number in Field: "Value1". I have a second table, "Customer_Criteria" which has a field "PassValue" that I want to compare against. My expression builder statement is:
IIf([txt_Value1]<(DLookUp("[PassValue]","[Customer_Criteria]","[Customer] = 'ABC'")),"TRUE","FALSE")
This statement always returns false, regardless of what the correct logical result is.
I've tested it, writing:
IIf(1<(DLookUp("[PassValue]","[Customer_Criteria]","[Customer] = 'ABC'")),"TRUE","FALSE")
And I get the correct results. Also, if I write:
IIf([txt_Value1]< 1,"TRUE","FALSE")
I get the correct results. What am I missing to compare the textbox value vs. the Dlookup?
As I understand, both fields are numeric. Access may consider those fields as text, so for correct comparing use type conversion.
Try this:
IIf(CLng(Nz([txt_Value1],0))< _
CLng(Nz(DLookUp("[PassValue]","[Customer_Criteria]","[Customer] = 'ABC'"),0)), _
"TRUE","FALSE")
Nz required if fields may contain NULL values, in this case type conversion function will return error.
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
Is there any way to convert one column and be able to reference all the other columns without naming them explicitly?
Normally I would do this:
SELECT
,[Id]
,[Name]
,CONVERT(VARCHAR(10),[CreateDate], 104) as [CreateDate]
FROM Customers
What I could do in the perfect world would be:
SELECT
*
,CONVERT(VARCHAR(10),[CreateDate], 104) as [CreateDate]
FROM Customers
Where * would mean all columns that are not explicitly stated in the query.
Is there a keyword that enables one to do this or is there some other way? Please keep in mind that it has to be doable in a query - no changing tables, making views, SPs or something else.
There isn't a programmatic way to say "all the columns except this one" unless you wanted to build dynamic SQL from sys.columns based on a list you provide the query (it would be very difficult to derive the list of referenced columns from the query dynamically, especially as you introduce joins, where clauses, etc).
But there is a pretty trivial way to do this without typing them all. Just expand your table in Object Explorer, and drag the "Columns" node onto the query editor window. Now just remove the CreateDate column from the list.
What I like to do to avoid typing a long list of fields is select the table name in the editor and then press alt-f1. That is the same thing than typing "sp_help table". You will get a result set with all the column names of that table. I copy that list into the editor and add the commas.
An easy way to add commas at the end of all the lines by using the search and replace in the editor:
Select only the lines with the column name.
Check "Use" and select "Regular Expressions" from the drop down.
In the "Find What" type $ (Dollar sign means end of the line)
in the "Replace With" type ,
That will add a comma to the end of each selected line.
Another way is to right click on the table in the Object Explorer and click on "select top 1000" option that will create a script for you in another text editor window.
How do I bind a text box with a field, which doesn't belong to form's "Record Source" table, through the Design View?
Example: I have "Order.cust_id" (Record Source=Order) and I want to display "Customers.name". I believe it is trivial but I have no experience with MS Access. I tried to use the text box "Control Source" property but no luck.
One method would be to convert the text box to a combo box. Then set the row source to include both the cust_Id and the Customer.Name from the customer table. SQL statement example
Select Cust_ID, Name From Customer
Order By Name;
By setting the number of columns to 2 and the column widths; the first column as zero (i.e. "0;6") then the foreign key would be hidden from the user and the customer name would be displayed.
Note this method does force you to have limit to list set to true.
Also you do end up with a drop down list which may not be what you want.
You can use DlookUp as the control source of a textbox:
=DlookUp("[Name]", "Customer", "ID=" & Cust_ID)
Syntax: What to look up, table name, where statement
The Where statement should follow the rules for Jet SQL, which means that you must use delimiters if the field is text or date format.
Note that Name is a very bad name indeed for anything. I suggest you rename the field immediately before things get worse.
It can be useful to know the error(s).
You could create a new View (e.g. OrdersAndCustomerNames), select all the columns you want to use in the form, then instead of using the Order table as Record Source, you would just switch to OrdersAndCustomerNames. You say you have no experience with MS Access, so I am guessing you are not building anything huge and overly complicated, so I would do it this way. I am quite sure it can be done more elegantly but this will do for now.