When I try to execute the transaction code DP80 (creating a quotation from a PM order) I get an error message number V1320 (in French, since I use the French version of SAP): it is asking for item category.
I so far have found that the solution is to define the Item Category via the transaction VOV4. Here's the image of the view I got by executing that transaction code. I'm supposed to enter the same value (SEIN) in the selected row, but I don't know how to do it because I can't type in it.
You can't edit a field that is a key. In this case you should select a row, copy it, modify the entry, press ENTER and the save the table.
Hope it helps.
The said error will come in case any value is set in CMIR. As you already found out the relevant transaction VOV4, you have copy the existing data and upon saving, one transport request would be generated, provided if you have authorization to do so. Else, ask some of your team members who have this authorization and do it.
By the way, do you maintain Customer Material Info record where this field (Usage) will come into picture
Related
I'm new to Access but have many years experience using "enterprise" databases. I'm having trouble implementing a simple task and suspect that my preconceptions are causing me to miss the point so I'm asking for some help.
The simple task is using Access forms for Data Entry that populates two tables: Customer and CustomerAddress (can be multiple addresses per customer).
The Customer table has primary key CustomerID. The CustomerAddress table has primary key CustomerAddressID and CustomerID as a foreign key with RI on that relationship.
Form1 is bound to the Customer table. After entering info for various fields, the user can click a button to display Form2 which is bound to CustomerAddress and enables data entry for multiple addresses.
Form1 passes the CustomerID (assigned by Access) to Form2. Form2 is not a subform due to size but it could be if that would solve the problem.
In a perfect world, I would want all the new data from both Form1 and Form2 to be committed together. Presumably I could do this using unbound forms and code the insert statements inside a single transaction.
Question 1: Is there a way to do this using bound forms?
If I use Form1 without ever clicking the "Address" button then a row is successfully added to the Customer table. The problem comes when trying to add CustomerAddress row(s) in Form2 before the Customer row has been added to the table.
In Form2, if the CustomerID is not used, then there is an insert error because a CustomerAddress row cannot be added without a CustomerID.
If the CustomerID is used, then there is an insert error because the CustomerID does not exist on the Customer table yet (although the ID appears to have been "reserved").
It's not practical to force the Customer row to be added before opening Form2 as some Customer required fields are not present at that point in the workflow.
Question 2: Is there a way round this? It seems like a common requirement.
I could work around this by removing the RI so that the CustomerAddress rows can be added first, but this seems poor DB design and I'd also need clean-up logic for the case where the Customer add is subsequently cancelled.
As mentioned, I'm probably missing the point and there's a better approach. Any help much appreciated.
I think you would have the same problem regardless of which RDBMS you used if you are enforcing referential integrity. The CustomerID needs to exist in the Customer table before a record can exist in the CustomerAddress table. I'm guessing that CustomerID is an autonumber. What is probably confusing is that Access does immediately 'reserve' an autonumber as soon as a new record is started. However, it does not exist in the Customer table. If that record is never saved, that autonumber value is lost and the next record would get the next number. Requiring an address to be completed before saving the Customer record, sounds like a design problem. It doesn't seem logical. Personally, I would re-think the design. That said, one solution would be to create a temp table for addresses and bind your CustomerAddress form to that. Then, when the customer record is saved, you would run an append query to add the new addresses to the CustomerAddress table. Remember, though, that if a user enters some addresses and the Customer record is never saved, all of that data entry is lost.
With regard to your statement:
It's not practical to force the Customer row to be added before opening Form2 as some Customer required fields are not present at that point in the workflow.
You are correct that you won't be able to insert the Customer row if the "required but not yet known" fields have their Required property set to Yes (i.e., NOT NULL). However, with Access 2010 and later you could use an event-driven data macro to make such fields "not required" on Insert but "required" on Update. In your case, you could
allow the Customer record to be inserted without the "eventually required" fields,
allow the addition of CustomerAddress records (with RI enabled), and then
re-open the Customer record for updating, with the data macro now enforcing the "required" status of the other fields.
The Before Change data macro might look something like this:
I think the answer lies within your Question 1. Yes there is a way to do this with bound forms, and would be the approach I would use.
Form1 is bound to the Customer table. Add Form 2 onto Form 1 as a subform. Select / highlight Form 2, goto the properties sheet. On the Data tab, set the Link Master Field to CustomerID and Link Child Fields to CustomerID.
Then after any action taken on Form 1, requery Form 2.
I think this will get you started and at least should give you an idea on how to proceed once completed.
I fail to see why both must be or one would even want to submit both customer and a record from the child table at the same time.
What about when you want to add an additional address, then that add address button and code now will have to check + test if the main customer already exists, and use separate logic to deal if the customer record exists, or does not. And what about if a user has entered the customer name and info, and does not yet have the address as the customer on the phone might have just moved and has to call back with the new address. I can think of another half dozen cases in which building a design in which both customer and customer address records MUST be added at the same time.
As others noted, you going to have this issue with any relational database, including Access. I should also point out that Access works EXACTLY the same here if you use Access as a front end to SQL server or Oracle.
So it makes little sense to build a different UI and coding process for adding the customer and the address, and then a DIFFERENT set of rules and UI for adding additional address over time. So build a form to search + find a customer, and add that customer and display that customer. Once that process is done, then you add the process (and UI part) to allow the user to view, or add address to that customer. I don’t think I ever seen a UI with separate forms to add/edit customer and a separate form to allow additional address to have some requirement that they are submitted together at the same time.
If the user bails out of the Address because they realize the address is not available, wrong etc., this should not suggest that the customer information entered so far be dumped and not added. If the user after bailing from adding the address (say close or cancel that form), then you return to the customer form. If the user decides at that point in time for some strange reason they do NOT want the customer in the system anymore, then provide a delete button.
If the business rules are that one MUST ALWAYS have at least one address in all cases, then upon closing the customer form you don’t allow the form to be closed and request that that user enter at least one address for this user. And perhaps they bumped or hit the wrong key to exit the address enter part – no need to penalize that user and force them to re-enter the customer info. So don’t let them exit the customer form until they enter an address or provide them (suggest to the user) they can delete/remove the customer fi they want to exit.
If you use a form + sub form setup, then zero code is required for the relational part. And a tab control gets you both forms can be near full screen size. (no need to launch a separate form).
Of course you could write a bunch of code and placed everything in a transaction, but such is a waste of coding time for no benefits and amounts to theft of company hours and time when not required.
In my current project I need to check if a process Instance already exist. I should be able to check this against a value which is stored in the pipeline.
In WmMonitor I tried a few services but with none I was able to find the existing process.
Do I need to mark the pipeline variable as logged field to be able to find the process instance?
Mayeb someone can share an example?
Regards Dirk
Yes, you have to mark the field as a 'logged field' in order to be able to search for process instances with a certain value in this field. Use services from the package WmMonitor.
This is too long, so I used answer instead of comment.
As of my understanding, you have some data, for simplicity assume, that just one string represents the data. Let say this is in a DB table. You should have flag in same table - processed with values true/false (in DB typically 0/1) and there should be a scheduler creating processes for unprocessed data only.
So the pseudo code would be:
retrieve unprocessed data
for each record try to create process
if creation was successful, mark the data as processed and continue
in this scenario you do not need to check whether process was started already...
Feel free to comment if something is unclear ;-)
Friends,
I have a table that contains data on the two parents of students at a college. Each parent will be sent an email with a link to a web page that will display the parent data that we currently have on record (names, email addresses, mailing addresses, employment information, etc.), and will be able to edit the data in order to update our records.
Since each parent will receive a link to the same data, and will be able to update the same fields, there is the potential for both parents opening the data at the same time, and then one parent submitting changes, then the other submitting changes which would overwrite those submitted by the first parent.
In order to avoid this, I have thought of using the method I've read about in which a timestamp field exists in the parent data record, and that timestamp is used as a hidden field on the form. Then, if both parents load the form, they'll both have the same timestamp stored in the form. When the first parent submits her/his updates, though, the timestamp field will update, and when the form is submitted by the second parent, the timestamp from her/his form will not be the same as the timestamp in the table, and the program (a Perl CGI) would alert the 2nd parent to this fact, and tell them to reload the form or risk overwriting the data submitted by the first parent.
That will work, but the person for whom I'm creating this form has asked if, instead, there's a way to lock the record in the table as soon as the first parent loads the form, and if the second parent tries to load the form while the lock exists, the form will tell them to wait until later (or words to that effect). The lock would be in place either until the form is submitted by parent one, or until one hour (or some specific period of time) has passed. Is this even do-able? I've been Googling, and don't see specific examples of this having been done.
Is there some better solution to this issue of needing to prevent two people from updating the same record, and the second submitter overwriting data submitted by the first.
Thanks for any help you can provide!
Doug
*******to address the comment by "inspiredcoder," here are some more details about what I'm concerned with here:
What I'm trying to avoid having happen is that parent 1 opens the form and starts making changes to the data. Before parent 1 submits those changes, parent 2 opens the form and also starts making different changes to the same fields being edited by parent 1. Parent 1 then submits her/his changes. Parent 2 then submits her/his changes, overwriting the changes made by parent 1.
What I would prefer is that parent 2 would not be able to even begin making changes if parent 1 has opened the form. The changes made by both parents need to be captured, and not overwritten.
The method of using the timestamp as I describe in my initial post can be used to prevent parent 2 from overwriting the data, but it also will mean that they'd have to reload the form to see the changes submitted by parent 1, and in doing so, would lose any of the edits they'd made in the form prior to them trying to submit it and getting the notice to reload. I'd like to avoid them having to re-enter their changes, and the only way to accomplish this seems to be to prevent them from even opening the form if it is already being edited, but I'd want that "lock" on the form/data to timeout after an hour or so in case parent 1 walks away with the form open but unsubmitted.
*****To answer a question by "ThisSuitIsBlackNot": Each parent can edit the same fields. One field asks for activities in which the parents are involved. Let's say Parent 1 enters five activities. If Parent 2 sees the form before Parent 1's edits have been submitted, he/she may enter completely different items, which upon submission would overwrite the activities submitted by Parent 1. If, on the other hand, Parent 2 could be stopped from accessing the form until after Parent 1 has finished her/his edits, then when Parent 2 can load the form, she/he will see everything that Parent 1 entered, rather than an empty form field, and may choose to modify what Parent 1 submitted, overwrite it completely, or not make any changes.
There's a reason you're not finding any info on how to do this. It is a very tough problem that no one has a good solution for regardless of which tech stack you're using. In your case, I'm not convinced that it is actually a terribly important issue to solve because the data does not seem crucial or mission critical. And besides, if there are changes they will likely be the same.
I've been in many design discussions where this issue came up. After hours of arguing the result is always the same: Last one in wins.
That said, here are a couple of simpler ideas you could try:
Simply email both parents (or whoever's registered as a guardian) whenever data on that page changes. This solution is stupid simple and easy to implement. If you're already using email services in other parts of the app then it becomes nearly trivial.
Not so simple: Whenever a request is made to edit the data, create a hash of the data as is to send back with the response to the client. When the edited data is sent in to update the row, check the data against the hash. If the hashes don't match it means that someone else has modified the data while the other parent was looking at it. The trouble with this solution is that you have to create these hashes and lug them around through several layers of the app making your programming non-trivial.
This statement caught my eye in a later edit of your OP:
The changes made by both parents need to be captured, and not
overwritten.
That single business rule actually makes things quite simple for you. All you need to do is to ALWAYS create objects when they do not have a unique identifier (probably 0 or -1). When objects do have an ID, meaning they have already been created, you simply update.
There is an assumption here that edits will likely be performed non-destructively on the same data. e.g. One parent creating an activity and the other parent editing it. There is a chance of duplicate activities but that's a situation easily resolved with a delete.
This way, no one parent can overwrite the other's data blindly and unknowingly.
Regardless of what you do though, do not try to find a perfect solution. It just doesn't happen. I know, I've been writing line of business apps for over 15 years. Apply your time and talents to something that you can get right, which the application and its business rules.
I would suggest reading up on database isolation levels. I believe MySQL defaults to repeatable read. You can confirm your isolation level at the DB level by running "SHOW GLOBAL VARIABLES LIKE 'tx_isolation';" Each transaction in this configuration is already placing a lock. Whether it is getting a row level or escalating depends on factors such as how indexes are being hit etc, by the query. If you fire off transaction A to update a record then subsequently fire off transaction B, transaction B is already in a holding pattern until transaction A completes its work in this configuration. If you set this to read commited, reads no longer block each other with locking (updates, etc still place locks). In lieu of implicit locks on reads you can be explicit using the select for update to try and force a lock on the read.
I mention brushing up on locking mechanics as trying to brute force locking without extreme knowledge of the back end DB mechanics can lend itself to deadlock central.
It seems like in your scenario this is more about user perception that what they are reading is up to date when they submit the changes. The DB is really doing it's job as designed. I have seen architecture to address this user perception issue by only allowing one user in a record at a time (locking out other users from the record while someone is it) handled in some middle ware code, etc. Or by using SOA architecture to push notifications to users in the record that a changed occurred by another user.
If user #1 deletes a record in our Access 2007 database (SQL Server ODBC Linked Tables), other users will likely show #Deleted# in that record (on Datasheet View form). On some occasions this can cause problems because I have code that runs on the Form's current event and simply assumes that a valid record (or new record) exists.
Is there any reliable way to detect if the current record has been deleted? I'd like to wrap it in a function like this:
Public Function IsRecordDeleted(ByRef r As DAO.Recordset)
'what goes here?
End Function
I did find a RecordStatus property in the DAO reference at MSDN but that property appears to only be valid if the RecordSet is configured for batch updating. When I try to check it's value I get: Run-time error 3251 - Operation is not supported for this type of object.
I actually posted on another forum about this same problem a year or two ago. The recommendations given do not work:
DCount()
Bookmark and NoMatch of recordset
Checking for #Deleted in the PK or FK field
To me, this looks more like a general application design oversight than a simple problem that has a simple work-around.
If you make assumptions on the availability of records in important places, then you must take into account the possibility of deleted records as a major (and valid) state of your data.
It's possible -but I think unlikely- that you will find a workaround, but I think you should take a closer look at your overall design itself.
Some ways to tackle the issue, that may or may not be useful in your case, depending on how your data is contained and accessed by users:
Simply do not rely on the existence of records if you can't be sure they will be there.
Basically, rework your assumptions and modify your existing code to avoid relying on the mandatory existence of records.
Separation of responsibilities
Don't allow different users to have the same create/edit/delete rights to the same data. For instance, a Purchase Orders should belong to the user who created it. Don't allow other users to delete that order or its items separately.
Don't actually delete the entity, just allow the user to mark it as 'Cancelled' or 'Obsolete' and keep it in the database for historical reasons (or purge them later).
Alternatively, don't actually delete records, but add a hidden boolean field to mark them as 'deleted' when the user wants to remove them. You can then do some clean-up, say every night, and actually remove the marked records.
Of course, you will have to exclude these 'deleted' records from your queries and forms, etc, but data integrity will be preserved.
Make reports and lists of records read-only so users can't just delete them anywhere. For instance, if users can view Purchase Order items, don't allow them to remove that data except when they actually open the Purchase order details form.
Cache records locally so that if they disappear from the backend database, they would still be shown to the user viewing them until they refresh the list.
This is often useful for read-only reports: load the result of a query into a local table and bind that table instead of the query using live data.
The data being viewed may be slightly stale because it won't update in real-time (since it's cached locally) but for reports, it's generally ok (just provide a 'Refresh' button on your form to allow users to force the refresh).
Experiment with the various locking options (see database options and form record locking) to disallow deletion of records if someone else is accessing them.
Manage your own locking scheme.
As a last resort, you could record in a 'LockingStatus' table the ID and records that are currently being viewed or edited by someone else. For instance:
Table: LockStatus
Field: LockNature: Whether the record is being Edited or Viewed
Field: LockedTable: Name of the table of the record being locked
Field: LockedRecord: ID of the record being locked
Field: User: Name of the user holding the lock
Field: LockTime: DateTime of the lock creation, so you can detect
and remove stale locks
When a user is viewing or editing a record, first check if there is an existing entry in the table for that record. If there is one, then tell the user they can't perform the operation because someone else is viewing the data. If there is no existing entry, add one, allow edits, and remove the record once the edit is complete.
This is fraught with complexities since you need to track when a user is moving to another record so you can unlock the previous one, and if you're not careful, you may end-up with lots of stale locks, but it's been done before.
If you still really want to circumvent the deleted record issue, have a look where, in your VBA code, the Error 3167 "Record Deleted" occurs when you delete a record from another location.
Once you know where it occurs in your code, trap that error using On Error 3167 Goto YourErrHandler to handle that particular error gracefully (that will really depend on how your forms are designed and how you use your data).
Another alternative is to use a global error handler for access.
I know only of vbWatchdog. It's not free but it works extremely well and is very simple to integrate into an application.
This add-in integrates in your application and doesn't need to be installed separately for each user. Once setup, your application will be able to catch all errors at a high-level. So you will be able to catch 'Record Deleted' errors and deal with them in one place.
I ran into the same thing via code in the Form_Current event, and ended up here.
Error handling is the best (and only?) way to go here. For my own purposes, I was just running a few simple control updates in the current event, and so I wrote the error handler to recover from the errors I was getting
Private Sub Form_Current()
On Error GoTo handler
'do intended things here, e.g. attempt to access the value
'of a control even though the record may be deleted
Exit Sub
handler:
If Err.Number = 438 Or Err.Number = 13 Then
'type mismatch, probably due to deleted record, skip it
Resume Next
ElseIf Err.Number = 3167 Then
'record is deleted, skip it
Resume Next
Else
Err.Raise Err.Number, Err.Source, Err.Description
End If
End Sub
I was not reliably getting 3167 (record deleted), but when attempting to access value properties I seemed to be getting just the 3 errors trapped above.
If your current event is longer, or if it's risky to run over code like this, you could use a similar technique but deliberately provoke the error at the beginning the method (dummyvalue = SomeBoundControl.Value should do the trick) and then change the "Resume Next"s in the error handler to "Exit Sub".
You could check a field which is not blank for sure if the record still exists.
I use a date updated or date created field which is autofilled by the default value =Now() once the form is opened for the first time.
Since its value seems to change to an empty string if the record has been deleted, I can trigger
If Me.DateUpdated = "" Then
on the form itself (e.g. to skip actions in the closing procedure). This check might also work from other forms.
I have an Access database that is used to store basic info in a table such as first and last name. How would I go about adding the functionality to lookup by last name?
Is there a way to type in the last name and then hit like F12 or something like this? Can someone please point me in the right direction or provide me a link?
SELECT tblPatient.LName AS [Last], tblPatient.FName AS [First]
FROM tblPatient
WHERE (((tblPatient.LName)=[Enter Last Name]));
How do I tie this into my form now?
I'd suggest you create a form, with a textbox 'search' at the top, then either a listbox or subform below to display results.
The listbox record source would be:
SELECT tblPatient.LName, tblPatient.FName
FROM tblPatient
WHERE tblPatient.LName LIKE Forms!myForm!search & '*';
You can either add a Search button, which requeries the listbox, or do the requery via the Change event of the search textbox. The later may be slow if you have a large number of records; if that's the case, you could check that at least 3 (?) characters have been entered before calling the requery.
You just need to create a query in which you put =[?] as the "last name" value.
When you open that view, you'll be asked to type in a lookup value for that field.
Not sure if this is what you are trying to archieve, though...
This is probably a bit overkill for what you want to do, but I assume that you want to perform a search by last name. You should be able to glean the information you need from this article:
Build a search criteria form
http://www.everythingaccess.com/tutorials.asp?ID=Build-a-search-criteria-form
You can create queries in Access if the user you're targeting with the searchability has Access themselves.
From the main Access UI (assuming Access 2007), go to the Create tab and then select the "Query Wizard." Here is an article on the subject.
Otherwise you can create a program and connect to the MDB/ACCDB file running the query programmatically.
Seeing you wish to look up a name and populate the form based on the name selected, I suggest you need a combobox. There is even a wizard for doing exactly what you want. To start, you will need a form bound to a table or query, that is a form with a Record Source.
Add a combobox to your form
Select :
Find a record on my form based on the value I select in my combobox
Select the ID (primary key), Last and First name fields.
Access will display an example, suggesting that you hide the Key (id) column. Accept this.
Choose a name and finish.
There are a few other small things that could be done for neatness, but you will end up with a form that find the record you want. In addition, the combo will autocomplete if you type in a few letter.
If this is an mde, which your subsequent post seems to suggest it is, there is little you can do wuth out the original file. However, you could try opening the database while keeping the shift key held down and see if that allows you to edit. If you cannot get the original and the shift does not work, you could try rescuing the data, if it, too, is stored in this file.