I have an access database and I am using this SQL to update my product table after I use the product from my order.
Is there a way to have it check to see if I already hit the update button that updates it so I do not remove it twice form my stock.
UPDATE ProductT
INNER JOIN MaterialT ON MaterialT.ProductID = ProductT.ProductID
SET ProductT.Stock = ProductT.Stock - MaterialT.Quantity
WHERE MaterialT.WorkOrderID = [OrderID];
Assuming that your frontend is a form in MS Access (since you are only using the ms-access tag), a simple solution could be to set the Enabled property of the button to False as the first operation of the On Click event, and issue a call to DoEvents to immediately update the display.
However, rather than subtracting a stock quantity from your ProductT table, a better practice would be to maintain a Stock Transaction table, and insert a record into such table corresponding to the allocation of stock of your material to your product.
This approach has several advantages, for example:
You have a record of the stock that was allocated to each product, and hence an audit trail.
You can check the Stock Transaction table for existing records corresponding to your stock movement before inserting a new record, avoiding the circumstance that you are currently trying to solve.
The current stock of each material and the quantity of stock allocated to each product may be derived from your stock transaction table, either directly, or for stock checking purposes.
Related
I know that single queries in Mysql are executed in an atomic way (there is the autocommit mode enabled by default)
But look at this query:
Update products set Amount = Amount-1 Where Amount>0 AND ID_PRODUCT = 5;
But what about concurrency? Namely more than one user can exec about in the same time the same query. For instance 2 users buy the same product when the availability is 1. When they purchase the product there is one, but when in the backend the query is executed the other user has already purchased the product thus the condition Amount>0 is not satisfied and the update is not applied. I would kindly know if this model is robust and safe for my application?
Or I have to use a lock or something like that?
This statement is atomic. It can be run more than once, even concurrently, but you will need to pay close attention to the result to see if any rows were modified.
In the case of running out of stock you'll get a result indicating no rows were modified, or in other words, it failed to subtract stock due to the condition.
Some systems prefer to move the stock around from a stock table like this to another "order" table, much like a ledger, so you can be sure you're not subtracting inventory that then goes missing if not properly purchased. A ledger makes it easy to unwind and return stock if someone abandons an order, makes a return, etc.
Let's say I'm trying to create sample db schema for cinema reservation.
I have a Table "auditorium" with int capacity and i wish to be able to create as much 'bookings' record, but i want to be unable to create booking when the auditorium is fill.
So for example, lets say Auditiorium A has 100 seats. Then i wish to be able to insert 100 bookings that has FK to Auditorium A, and when i try to create 101'st booking i will have error or something like this.
This would normally be handled by a trigger -- in either MySQL or SQL Server.
One method is to have an Auditoria table that has a maximum capacity (or perhaps a maximum per event, if the configuration could change).
The Bookings table would have a trigger. When records are inserted, the number of records for the event would be compared to the capacity for the auditorium, and inserts that exceed the capacity would fail.
If the Auditoria have a fixed capacity and layout, you can also have a table with one row per seat. The booking would then be for a particular seat -- and the capacity issue is automatically taken care of (because no seats would be available).
Currently we have a ticket management system and like all ticketing systems it needs to assign cases in a round-robin manner to the agents. Also, at the same time the agent can apply their own filtering logic and work on their queue.
The problem,
The table with the tickets is very large now, spans over 10 million rows.
One ticket should never be assigned to two different users.
To solve the above problem, this is the flow we have,
Select query is fired with filter criteria and limit 0,1
The row returned by the above query is then selected based on id and locked for update.
Lastly we fire the update saying user X has picked the case.
While step 3 executes other user cannot get a lock on the same case, so they fire 3.a query may be multiple times to get the next available case.
As number of users increase this time in step 4 goes higher and higher.
We tried doing a select for update in query at step 4 itself, but it makes the entire query slow. Assuming this is because a huge number of rows in the select query.
Questions,
Is there a different approach we need to take altogether?
Would doing a select and update in a stored procedure ensure the same results as doing a select for update and then update?
P.S - I have asked the same question stackexchange.
The problem is that you are trying to use MySQL level locking to ensure that a ticket cannot be assigned to more than one person. This way there is no way to detect if a ticket is locked by a user.
I would implement an application level lock by adding 2 lock related fields to the tickets table: a timestamp when the lock was applied and a user id field telling you which user holds the lock. The lock related fields may be held in another table (shopping cart, for example can be used for this purpose).
When a user selects a ticket, then you try to update these lock fields with a conditional update statement:
update tickets
set lock_time=now(), lock_user=...
where ticket_id=... and lock_time is null
Values in place of ... are supplied by your application. lock_time is null criteria is there to make sure that if the ticket has already been selected by another user, then the later user does not override the lock. After the update statement check out the number of rows affected. If it is one, then the current user acquired the lock. If it is 0, then someone else locked the ticket.
If you have the locking data in another table, then place a unique restriction on the ticket id field in that table and use insert to acquire a lock. If the insert succeeds, then the lock is acquired. If it fails, then another user has locked the ticket.
The lock is usually held for a number of minutes, after that your application must release the lock (set locking fields to null or delete the locking record from the other table).
Let's say I have a table called tickets which has 4 rows, each representing a ticket to a show (in this scenario these are the last 4 tickets available to this show).
3 users are attempting a purchase simultaneously and each want to buy 2 tickets and all press their "purchase" button at the same time.
Is it enough to handle the assignment of each set of 2 via a TRANSACTION or do I need to explicitly call LOCK TABLE on each assignment to protect against the possibility that 2 of the tickets will be assigned to two users.
The desire is for one of them to get nothing and be told that the system was mistaken in thinking there were available tickets.
I'm confused by the documentation which says that the LOCK will be implicitly released when I start a TRANSACTION, and was hoping to get some clarity on the correct way to handle this.
If you use a transaction, MySQL takes care of locking automatically. That's the whole point of transactions -- they totally prevent any kind of interference due to overlapping requests.
You could use "optimistic locking": When updating the ticket as sold, make sure you include the condition that the ticket is still available. Then check if the update failed (you get a count of rows updated, can be 1 or 0).
For example, instead of
UPDATE tickets SET sold_to = ? WHERE id = ?
do
UPDATE tickets SET sold_to = ? WHERE id = ? AND sold_to IS NULL
This way, the database will assure that you don't get conflicting updates. No need for explict locking (the normal transaction isolation will be sufficient).
If you have two tickets, you still need to wrap the two calls into a single transaction (and roll back if either of them failed.
I have a MS Access db to handle our product pricing. One of my tables has all of our products in it with a yes/no, "checkbox", field field to identify if we bulk that product. I have a separate table that handles our bulk product pricing. Currently when I want to set up a bulk product I add it to our products table, check off the bulked so it removes it from the non-bulk price query, then add the product# to the bulk products table.
I'm pretty new to VBA but what I want is when the "Bulked" field is checked it takes the product code for the current row and insert it into the product code field in Bulked Products. Is that possible?
Yes, it is possible, you can run an update query in VBA, but I suggest that you do not do it. It will involve you checking whether the record already exists in the bulk table, if it does exists, if it matches, and rewinding if someone clicks by mistake. I do not believe you need two tables, you just need a field to indicate that the product is bulk.