Code to assign an ID when button is clicked - forms

I have designed a simple database to keep track of company contacts. Now, I am building a form to allow employees to add contacts to the database.
On the form itself, I have all the columns except the primary key (contactID) tied to a text box. I would like the contactID value to be (the total number of entered contacts + 1) when the Add button is clicked. Basically, the first contact entered will have a contactID of 1 (0 + 1 = 1). Maybe the COUNT command factors in?
So, I am looking for assistance with what code I should place in the .Click event. Perhaps it would help to know how similar FoxPro is to SQL.
Thanks

The method you recommend for assigning ContactIDs is not a good idea. If two people are using the application at the same time, they could each create a record with the same ContactID.
My recommendation is that you use VFP's AutoIncrementing Integer capability. That is, set the relevant column to be Integer (AutoInc) in the Table Designer. Then, each new row gets the next available value, but you don't have to do any work to make it happen.

There are various ways to do this. Probably the simplest is to attempt to lock the table with flock() when saving, and if successful do:
calc max id_field to lnMax
Then when inserting your new record use lnMax+1 as the id_field value. Don't forget to
unlock all
... after saving. You'll want to ensure that 'id_field' has an index tag on it, and that you handle the case where someone else might have the table locked.
You can also do it more 'automagically' with a stored procedure.

Related

MS Access Combobox "#Name?" error

I have a problem with a combobox in a form, which displays a "#Name?" error whenever I enter it to select a value.
I am creating a form in MS Access (specifically in Microsoft Office Professional Plus 2010) that is a general user interface, meaning that the form itself is not linked to a RecordSet of any kind.
In that form, I create a Combobox, which I link to a "TblSubsystem" table. The table is very simple and designed like that:
ID (primary key, autonumber)
SysShortName, text
SysFullName, text
When I try to select a value in the dropdown list, the testbox of the combobox just displays "#Name?" (actually as soon as I select the combobox, even before I select any value)
The relevant (I think) parameters of the combobox are:
Control Source= "=[TblSubsytem]![ID]"
Row Source= TblSubsystem
Row Source Type= Table/Query
Bound Column= 2
Column Count= 2
Column Width= 0cm;1cm
(I am trying to select and show the short code, but to get the ID as a value for the combobox)
I have another form in the same project, in which a identical setup (also on TblSubsystem) works just fine, with the same values for these parameters, but that Form is linked to a RecordSet (another table). As far as I can tell it is the only difference, so I guess I must be missing something around that, which will seem obvious once I see it...
I have looked for variation of "Ms Access combobox #Name? Error", on stackoverflow and more broadly on the net, but in two days, I haven't seen any post answering my questions. Some are close, but refer to a much more complicated setup, while I think mine should have been pretty straight forward. Trying to adapt the solution to my case (includind recreating the combobox or decompiling the database) didn't help.
Here it was, long question, sorry about that, but hopefully precise enough for some of you guys to help on that. I thank you in advance for any help I can get on that.
#Name is a binding issue. Try setting your bound column to one, that way it only records your primary key and see if that works.
Edit: You've got the combobox referencing your table's primary key as your control source. Keep in mind the control source is the value that is being altered by the application user. Here are some key things to think about when working with comboboxes:
The control source should (typically) reference the foreign key of your table
The row source should reference the text that you want displayed in the box
Bound column should be set to 1, unless your application design requires you to update two fields simultaneously, which is an uncommon practice.
Set your column width to 0;1. This will hide the first field in your row source, which should be your foreign key
An example would look like this:
Control Source: EmployeeID --123456
Row Source: EmployeeID, EmployeeName --123456 | John Doe
A bound column set to 1 would record the value 1234556. A bound column set to 2 would record 123456, John Doe

MS Access Form and Tables

I have a specific question regarding the utilization of three tables in a database. Table 1 is called Personnel, and lists the names of the staff.
Tables 2 and 3 are identical, just listing two different types of overtime (long and short), along with the hours of the OT, Date of the OT, and Assigned to/Picked fields that are empty.
Here is the idea, I just dont know how to implement it. I would like to create a form for people to enter their OT picks, then automatically move to the next person on the list. So Rich Riphon, as an example, would be up first, would click on the link I would send, and a form would open up, showing his name, populated by the first table, and showing two drop down menus, populated from the Long OT and Short OT tables. He would select one from each (or None, which would be a option) and Submit it.
The form action would be to place his name in the Assigned field for the OT he picked, and place a Yes in the Picked field.
When the next person in the list opens the form, it has moved down to number 2 on the Personnel list, Cheryl Peterson, and shows her the remaining OT selections (excluding those that have a Yes in the Picked column).
Any suggestions or comments or better ways to do this would be appreciated.
First, I don't think ms access would be able to (easily) kick off the process based on a hyperlink. You may be able to do something by passing a macro name to a cmd prompt but it would take some mastery to get it working properly. Could you instead create a login form to get the current user? If you do that you don't really need to display the personnel list, just keep track of who has not yet responded to the OT request. Essentially at that point all you would need on your form is a listing of the available OT and a button that creates the assignment. Also it may be easier (and a better design) to only have one table for the OT listings and add a column for the type of overtime (long/short).
What if Cheryl isn't the 2nd person to get the form? Your concept goes out the window.
Instead, I would keep a table of all user names, and their security level. managers can see everything, individual users can only see their record. This would be done by using a query behind the OT Picks form, and either filtering by the current user or not filtering at all. I have done many of these types of "user control" databases and they all have worked well.
As for the actual OT tracking, I agree with Steve's post in that it should be done in one table This would be the preferred method of a concept referred to as "normalizing data". You really want to store as little data as possible to keep the size of your database down. As an example, your Login table would have the following fields:
UserID
FirstName
LastName
SecurityLevel
Address1
Address2
City
State
Phone
Etc... (whatever relevant info pertains to that person)
Your OT table would look like this:
UserID
OTDate
OTHours
OTType
Etc... (whatever else is relevant to OT)
You would then join those 2 tables on the UserID fields in both tables any time you needed to write a query to report OT hours or whatever.

How can I create a new primary key in a FileMaker table and then modify an existing relationship to be based on the newly created key?

I have quite the request. A developer created our database that has multiple Layouts with a relationship tree that is very messy. Had another developer come in, take a look at it, he said that it would be too time consuming and painful to deconstruct our system, consider creating a script for now so that you can work around it until it can be fixed. Here's the dilemma: I've got information on one page that is supposed to reference information on a number of different pages utilizing tabs and portals. However, all the information is linked to a username. This username is not static/serialized or what have you. Therefore, if the issue is not caught right away a great deal of information can be linked to this person's 'page'. If the name is incorrect and someone tries to alter the username even slightly, it breaks that relationship and starts a new one. The information does not disappear, but it is basically sitting in limbo somewhere until you change the name back to the original. I've actually tried exporting the information, changing the information that doesn't match, i.e. changing a name from Jon.Smith to John.Smith, and then importing the information to a new 'page' for that person with unsuccessful results. Which brings me to my question, is a script going to be able to fix this problem? Likewise, are there any suggestions to how to create this script? I apologize, but I have very little experience with DataBase management at all, and am not sure why this project fell upon me. Any help would be GREATLY appreciated.
Well, as a general answer, just about anything that a user can do in FileMaker (and by user, I mean non-developer, so activities such as defining the database structure, writing scripts, etc., are excluded) can be scripted. So if you're able to "solve" the problem by resetting a field's value, for example, then, yes, a script can do that.
Regarding your specific trouble, a script probably doesn't need to export the records, but could reset the values for the field within FileMaker. This could be done either by looping through the records that need to be changed or by using the Replace Field Contents script step. So a script could do something like this:
Go to Layout[MyLayout] // Go to a layout that is attached to the table you need to search.
Perform Find[Restore] // Restore a find that will show the records you need to change.
Replace Field Contents[Table::Field; "New Value"]
Offering more advice than this would require actually seeing the database and understanding more about your specific needs.
wchsTech4, you are in luck because your problem is easy to fix. You don't even need a script.
BACK UP YOUR FILE(S) FIRST. Then:
1) Create two new fields:
id (person table)
Options for id: Auto-enter serial number
person_id (the table related to person)
2) Generate serial numbers for the new id field in the person table.
Navigate to the person layout.
'Records' > 'Show all records'
Click in the id field and select 'Records' > 'Replace field contents.'
Choose 'Replace with serial numbers' and accept the defaults. Be sure to check the box to update your next serial number.
3) Place the serial numbers you just generated in the related table.
Navigate to the related layout.
'Records' > 'Show all records'
Click in the person_id field and select 'Records' > 'Replace field contents.'
Choose 'Specify' next to 'Replace with calculated results.'
In the drop down on the top left, select the related person table.
Double click the id field (your calculation should be person::id, with person replaced with the name of your table).
Click 'OK' and then 'Replace.'
4) Change the relationship.
Select 'File' > 'Manage' > 'Database.'
Navigate to the relationship tab.
Change the relationship from being based on name to id.
5) Test everything. Should work.
There is a chance that your related records are being created in such a manner that you also need to modify a script, website, or something else not mentioned here to have your fix work going forward. That is important to investigate.

One (probably unbound) Access 2003 form to create multiple records

I've been recruited to work on a form for tracking specimens. Each specimen is associated with a subject; each specimen also has a particular slot in a 9 x 9 storage box. For ease of data entry, I think it would be best if the Access form mirrored the box itself (and the paper forms that will be used to enter data into Access): nine columns by nine rows, with each element consisting basically of a text box for the specimen ID. This is basically how I'd like it to look:
So the data entry person would essentially type in the box number and specimen IDs, then click "Create Records" to pop all of those records into existence (you can see some other stuff going on here, but that's not really important right now). I'm not really sure about the best way to code this, however. Right now, the best process I can think of is to: 1) run an insert query to create the box if it doesn't exist, 2) run an insert query to create the subject (person), if it doesn't exist, and 3) run an insert query for each specimen, hard-coding in its row and column (e.g. box_col = 'A', box_row = '1').
Note: the subject ID and specimen ID would both be parsed out of the ID field - it's goofy, not my idea, but that's how it's set up. I can handle that, though.
This is a certainly a kludge, but I'm not sure what else to do and most of what I've googled up hasn't been pertinent to multiple-record creation from a single form. Is there a better way to do this? Should I simply abandon the idea and go with a more traditional bound subform approach?
This could be all done in a sub form - however, I assume for simplicity (less clicks, easier user experience, and intuition) you've designed it so that the end user sees everything he /she need to enter. There is nothing wrong with doing it this way. Once the data is all entered just have a button on the form that does the multiple inserts at once.
Start at 1 and include 9 iterations each time issuing a new INSERT statement.
Once the statement has been completed I would personally put a little check mark next to each row so that if an insert succeded it would check it true, else false. You could be nifty and use a green image / red image. After it has completed the process all fields should be cleared allowing additional entry.
I don't see an issue with what you have.
FRIG. I just lost ten minutes of typing. This is why I don't care for web based forms. Although to be fair this is the first time this has happened on StackOverflow.
Do you really need to view the data later in the same format as it's entered. If they can just view regular subforms that's at least half the work as you no longer need to do updates of this form.
Also note that there is a lifetime amaximum of 768, if I recall correctly, controls per form. 9 x 9 x 2 is 162 so you'll be ok there. However if you decide to delete and recreate lots of cotrols you could be in trouble. If you do hit that limit I think saving the form under a separate name should reset the counter.
Note you can use the following construct to refer to controls and make life easier.
Me.Controls("abc" & Row & column)
For example in the After Update of the type control you could use
call InsertRecords(3, "B")
sub InsertRecords(row as integer, Column as string)
....
cboTypeValue = Me.Controls("cboTypeID" & Row & Column)
....
This could be used as some kind of native access controls only grid.
If someone would post an example of how to create custom unbound subform with row for each unbound record and a code to loop and save it to the tables would be just great.
There wouldn't be as much controls and it wouldn't have any limits by the numbers of fields on form.

Filemaker: Best way to set a certain field in every related record

I have a FileMaker script which calculates a value. I have 1 record from table A from which a relation points to n records of table B. What is the best way to set B::Field to this value for each of these n related records?
Doing Set Field [B::Field; $Value] will only set the value of the first of the n related records. What works however is the following:
Go to Related Record [Show only related records; From table: "B"; Using layout: "B_layout" (B)]
Loop
Set Field [B::Field; $Value]
Go To Record/Request/Page [Next; Exit after last]
End Loop
Go to Layout [original layout]
Is there a better way to accomplish this? I dislike the fact that in order to set some value (model) programmatically (controller), I have to create a layout (view) and switch to it, even though the user is not supposed to notice anything like a changing view.
FileMaker always was primarily an end-user tool, so all its scripts are more like macros that repeat user actions. It nowhere near as flexible as programmer-oriented environments. To go to another layout is, actually, a standard method to manipulate related values. You would have to do this anyway if you, say, want to duplicate a related record or print a report.
So:
Your script is quite good, except that you can use the Replace Field Contents script step. Also add Freeze Window script step in the beginning; it will prevent the screen from updating.
If you have a portal to the related table, you may loop over portal rows.
FileMaker plug-in API can execute SQL and there are some plug-ins that expose this functionality. So if you really want, this is also an option.
I myself would prefer the first variant.
Loop through a Portal of Related Records
Looping through a portal that has the related records and setting the field has a couple of advantages over either Replace or Go To Record, Set Field Loop.
You don't have to leave the layout. The portal can be hidden or place off screen if it isn't already on the layout.
You can do it transactionally. IE you can make sure that either all the records get edited or none of them do. This is important since in a multi-user networked solution, records may not always be editable. Neither replace or looping through the records without a portal is transaction safe.
Here is some info on FileMaker transactions.
You can loop through a portal using Go To Portal Row. Like so:
Go To Portal Row [First]
Loop
Set Field [B::Field; $Value]
Go To Portal Row [Next; Exit after last]
End Loop
It depends on what you're using the value for. If you need to hard wire a certain field, then it doesn't sound like you've got a very normalised data structure. The simplest way would be a calculation in TableB instead of a stored field, or if this is something that is stored, could it be a lookup field instead that is set on record creation?
What is the field in TableB being used for and how?