Lock user record and prevent editing? - sql-server-2008

while working on my new application customers came back to me with specific requirement. They would like to prevent multiple users editing same record at the same time. For example if User 1 login the application, search for the record and then select the record. There is few different forms that shows the data for selected record. For example that can be demographic form, family info, etc. Let's say we have User 2 who logged in and selects the same record. In this situation we would like to prevent both of them editing any of the forms at the same time. I'm wondering if my approach is a good fit or there is something that would work better. What I do is next:
User selects the record, the automatically save this record in Lock table
Lock table has RecID (autoincrement field), UserID(unique id for each user in the system), SelectedID (Record that user selected) and DateTime (Timestamp)
Then I disable all Edit buttons in each form on the front end.
On the back end I join Lock table to every update query. For example:
<cfquery name="updateDemo" datasource="#dsn#">
Update dbo.Demographic
Set LastName = 'Kelly',
FirstName = 'Mike',
DOB = '07/06/1967'
From Demographic AS D
Left Outer Join dbo.Lock AS L
On L.SelectedID = D.SelectedID
Where RecID = '123132'
And L.UserID = Session.UserID
</cfquery>
In query above I join table that will be update to the Lock table SelectedID. That way only selected record is update and we are making sure that UserID in Lock table is matching Session User ID. Users can unlock the Selected Record any time by clicking unlock button in the system. I'm not sure if this method is the best. So far I can't find any issues but this code is still in development phase. If anyone have any suggestions please let me know. I use SQL 2008, ColdFusion 2016 with JQuery and Bootstrap 3 on the front end.

Your solution should work but it sounds a bit complicated. I would:
Add an updatedAt column to the Demographic table and update it
with getdate() on save.
Add the updatedAt field to your form and prefill it with the record data from the table.
When updating make sure that the updatedAt field in the table equals to the updatedAt field in the form data. Throw an error if the updatedAt
field in the table is newer than the updatedAt data in your form.

Here is how I have solved this in the past.
For information that will need this kind of 'locking' add a numeric column named something like 'version'.
Every time a row in this table is saved, increment the value of 'version' by 1.
Include this value in any form used to edit the table.
If user A pulls up a record at the same time as user B, but user B saves the information first, the 'version' will be different when User A submits their form.
On form submit, do a check that the 'version' passed in matches the 'version' from the DB. If it does...update the table,. If it doesn't redirect the user to the form and let them know they are not updating the most recent 'version' of the data and give them an option to load the updated data.

Related

Sequential Number in Access Form Based on Field Selection

Hoping someone can assist here, I'm fairly new to SQL but yet the most experienced person in the office so this job has fallen to me.
I'm trying to build a form that will insert customer orders into production scheduling. The form allows users to select a machine from the machine list table, however what I need it to do after that is find the last job number for that specific machine and show the next sequential number in a text box; and that's where I'm stuck. The goal is that when the production user is adding an order to the database, by selecting their machine the next available job number is automatically populated. The information entered will be saved to a master scheduling table.
I've got a query built that pulls the entire list of machine and job combinations, as my goal was to build a macro that could search from that list, but so far I haven't gained any traction. Any help/advice would be appreciated!
Welcome to SO.
My suggestion would be to create a table to hold the sequence numbers. For the sake of this example, let's call it ProdSeq, which means Production Sequences. As part of this table definition, I would use Data Macros (Access 2010 and up) in order to assign the sequences as records are added. I would use a Unique index in order to ensure no duplicates are created.
Table: ProdSeq (Field Definitions)
MachineID (Number - Long) - References Machine ID in Machines Table
ProdSeq (Number - Long) - Incremented for each machine
OrderID (Number - Long) - References Order ID in Orders Table
Indexes
Under the Design ribbon tab when designing the ProdSeq table, click the Indexes button.
Create an Index called UniqueKey
Row 1: Index Name = UniqueKey, Field Name = MachineID
Row 2: Index Name = Leave Blank, Field Name = ProdSequence
Click on Row 1, Column 1 and set the following Index Properties:
Primary = Yes
Unique = Yes
Ignore Nulls = No
Data Macros
Under the Design ribbon tab when designing the ProdSeq table, click the Create Data Macros button, and then the Before Change button. Enter the following data macro: (Pastebin link)
Create the Before Change data macro and set it as follows:
If [IsInsert] Then
SetLocalVar
Name LatestProdSequence
Expression = 0
Look Up A Record In ProdSeq
Where Condition =[ProdSeqLookup].[MachineID]=[ProdSeq].[MachineID] And
[ProdSeqLookup].[LatestSeq] = True
Alias ProdSeqLookup
SetLocalVar
Name LatestProdSequence
Expression =[ProdSeqLookup].[ProdSequence]
SetField
Name ProdSeq.ProdSequence
Value = [LatestProdSequence]+1
SetField
Name ProdSeq.LatestSeq
Value = True
End If
Pay special attention to the fact that only one SetLocalVar is within the LookUpRecord clause. Use the collapse / expand (-/+) button on LookUpRecord to make sure.
Create the After Insert data macro and set it as follows: (Pastebin Link)
For Each Record In ProdSeq
Where Condition = [ProdSeqFlagFix].[MachineID]=[ProdSeq].[MachineID] And
[ProdSeqFlagFix].[LatestSeq]=True And
[ProdSeqFlagFix].[ProdSequence]<>[ProdSeq].[ProdSequence]
EditRecord
SetField
Name ProdSeqFlagFix.LatestSeq
Value = False
End EditRecord
Test it Out
You can create this in a blank database in order to see what I am talking about. You should be able to adapt it to your specific situation.
Form
On your form, when the user selects a machine and order, you can use VBA in order to check for an existing record in ProdSeq, and fetch the ID. If no record exists, then you can create one, and then return the ProdSeq ID to the form.
Note: Depending on your design, you may also need to create a Data Macro on the Schedules table. Suppose someone creates a schedule with a specific machine and order and reserves a production slot. Now assume they change the Order ID .. we have a production slot reserved in error. So if this applies, you'll also need an AfterUpdate data macro on the Scheduling table that checks to see if [old].OrderID <> [Schedule].OrderID - and if they do differ, to remove the Production slot from the schedule table and the Prod Sequence table.
As I understand, you need to add suggested value for job number when you add new record to the table. If so, you can use, for instance DMax function. Here is example of VBA code for this, it can be called when you add new record:
Me.MyTextBox = DMax("JobField", "JobsTable") + 1
I supposed that JobField, which contains job numbers has Number data type.
Also you can use this function inside any query as a calculated field.

MS-Access combobox adding record to table that is supposed to be a lookup

I have a form with subforms that has been created from a query that I created. This query has information from 6 tables. The form is separated into basically 3 sections.
The main form is Credit Union information, first subform is Branch information and the second subform is Circuit information based on the branch record that is selected. In the Branch subform I have a combobox that is set up to display the TimeZones table info so that when creating a new branch in the form you can automatically select the timezone.
The issue I am having is that when I select the timezone and save the record, a new record is created in the Time zone table with the same text information just a different ID, rather then what I expect it to do which is add the existing time zone ID to the new branch record.
Based on your question, it sounds like you are hoping to use information from the time zone table to add the field "timezone" to your Branch table. If I'm correct, you would have to add that field to your Branch table in design view first. Then, you go to your combobox properties within your form. Next to row source, type "SELECT [TimeZones].[timezone] FROM [TimeZones] - making sure of course the spelling matches the tables/fields.
Thanks for the input but I was able to figure it out. Instead of keeping the "Time Zone" field on the Brnaches table as a text input or matching the Timezone ID from the Time Zone table, I changed the Brnaches table "TimeZone" field to be a lookup field that queried the Timzone table before the information was added to a Form. Then when the form was created, the timezone entry was already a combobox and already queried the Timzone Table.

Display specific records depending on user's choice

I have a MS 2010 Access Report that needs to be populated by records that a user pre-chooses. For example.
Form1 has 2 fields, LOT# (which is record id) and CheckoffBox (unbound).
User checks which Lot#'s (records) he wants displayed, then clicks REPORT button. Report only shows selected records.
Can someone help me create the code?
In order to allow the user to use a check box to select multiple records, the list presented in form 1 must be based on a table that has LOT# and a yes/no field. (ie form 1 must be based on a query or a table that ahs this yes/no field).
If only one user will ever use this at any one time then you can simply add a yes/No field to the table that has all the LOT# values.
On your report you then only print those lot numbers that are checked.
Your report simply has to have SQL with a where clause that only print records that have the Yes/No field ticked. (=true =-1).
If many users are going to use this form at the same time it gets more complicated as obviously they all need to have their own "set of yes/no fields".
So you would need to copy the table with the LOT# into a temp table for use by each user (it might have a primary key of USERID, LOT#, or it might be a table with just LOT# and yes/no fields, that only a user can access - ie in their own copy of the database file that has the front end forms).
Anyway, assuming it's a single user, creating the above should be quite straight forwards.
On opening form 1, you might use the form_open event to run a SQL statement that sets all the Yes/No values to No. Although you might not want to do this.
Use
docmd.SetWarnings false
Docmd.runsql "UPDATE theTable SET YesnoField = 0 WHERE YesnoField = -1;"
docmd.SetWarnings true
Let me know if you can take it from here.

How to select multiple records and change their value at once

Here is my problem and I do not know where and how to start to search about this.
In a MS Access database users will have a list of records returned from a query. Let's say employees which are active (employed). This table has a related table let's say departments (related through departmentID in both table).
What I want to do is to make form (or something else which would do the same job), where user will select some records (probably with checkboxes associated with each record) and there will be a single combobox with department names. When user selects a department name, its departmentID should be saved into departmentID field of these records.
I have created a form with a query of active employees (form with multiple items). And put an extra field in Detail section with a checkbox. In Form footer I have a combobox with Department names and IDs (not shown to user), and a button to save values.
I have to now figure out, how to select all rows/records with a checked checkbox and update them. I am by the way familiar with VB and SQL.
I would appreciate any idea/knowledge on how to solve this.
An extra field in the Detail section won't help you if you don't link it with a data field in the displayed table. If you can do that, then you have simply to make a VBA function to update all selected rows, and refresh the recordset.
If you cannot modify your table, you'll have to create a new table with just the key columns of your master table, and manage it via VBA. Better to use the first option if you can, it pollutes your schema, but in most cases that won't be a problem for an Access database.

Timestamp is generated for next record, as opposed to current record

I have a slight issue with MS-Access, which is as follows.
I have a table with a Timestamp column (the format of the field is Date/Time, the default value is Now()). The issue is that whenever I create a new record, the timestamp is set for the next record I am going to create, as opposed to the record I am creating.
This means that I create record 50, and the Timestamp is set for record 51. If I come back a week later, and create record 51, the Timestamp for record 51 will be a week out, and the timestamp will be set for record 52, which I will be creating at some point in the future.
You can re-create the problem by firing up MS-Access, creating a new table with a couple of fields, one of which is Date/Time and setting the Default Value of this field to Now().
Is this by design, or am I doing something dumb? If it is by design, how can I implement the type of Timestamp that I want (one where the Date/Time is set as the record is created) in MS-Access? If I am doing something dumb, what exactly am I doing?
Edit: Below is a screenshot of a newly created Access table:
I add some text to record one, the Timestamp gets set for record two:
I allow some time to pass, put some data into record two, and the timestamp doesn't change, and now record three has a timestamp:
If I close and open the table, the Timestamp for the (New) record gets updated to whenever I opened the table:
I allow some time to pass, update the record and the Timestamp stays at the time I opened the table:
As is already revealed in the comments, this problem comes from editing in the table with Now() set as the Default for your TimeStamp field.
I suggest you create a form instead of editing in the table. If you want it to look similar just use a datasheet form. Then on the Form's BeforeUpdate event put code in like this:
Me!TimeStamp = Now()
As a side note, I wouldn't use TimeStamp as a field name. Some RDBMS such as SQL Server have a data type called TimeStamp. It's best to avoid using field names that are data types or reserved words. Moving an Access database to SQL Server is extremely common and you could have problems when you try to do it.
Instead, I would create two fields. One called DateTimeEntered and another called DateTimeModified. I consider these two fields to be necessary in pretty much every table I make. If you ever want to do any kind of synchronization of records you'll wish you had at least a DateTimeModified field.