I am writing a database of warehouse of groceries. I have tables clients, workers, orders, products and some which are not really important in that question.
I want to avoid a problem where client makes a new order for product but there isn't enough amount of this product in our warehouse.
I have to make a transaction which avoid situation when two clients are making a new order at the same time and one of them ordered for example the last item while making order by the second client.
I don't really know how to do it because only workers can decrease amount of every product. So I want so that while deleting a order (which was made by client) by worker the amount of available product was decreased.
I know that I can put it into trigger but the question is:
how to define the transaction of ordering product with checking available amount. Should I count the difference between avalaible
amount in table Products and amount of ordered product by the
time(unrealized orders).
How to do it ?
for orders, you have to manage Stock of that product and every time when someone going to make an order you have to check product availability or not.
One thing you could do is place a trigger on the orders table, that subtracts quantity from the products table and raises an exception if the amount is negative. The trigger would have like:
update products set current_quantity = current_quantity - :new.amount_purchased
where id = :new.product_id
returning current_quantity into l_current_quantity;
if l_current_quantity < 0 then
raise_application_error( -20001, 'Amount ordered larger than remaining quantity.' );
end if;
You'll have to handle the exception in your ordering procedure.
Related
I'm creating a Motorcycle store system, i wondering if i need to create one table that contains orders, the sales orders and the purchases orders with a column that will be called OrderType that determine if its purchase order or sale order
the same with Payments, money that i pay to supplier and money that customer pay to me, should be in table that called payment and column that determine if its outgoing payment or income
is that ok? or i need to create other tables
I would consider against it... Purchases are from a vendor YOU get the products from to build/fix/manufacture something.
Sales orders would have a customer you are selling to and thus would be foreign keys to different tables... unless your customer table has your vendors too and that has some column to identify difference as Vendor vs Customer.
Additionally, as you expand your design development and queries, purchasing history, etc., it may be more beneficial to have them separate.
You can create a single table. Whether this is good design or unfortunate design depends on how you use the data. How many times do you ever want to query these two datasets as if they were one dataset? How many times to you query them separately?
I am trying to write a Check to make sure that a customer can only buy 10 of a certain product type (smartphone) and 4 of another product type(tv), and buy another product only during morning(before 12:30). The table is
invoice(PK invoice_no, FK product, amount, customer_name,time, FK opening_time )
Check (amount >10) would check the amount but I want to limit only a few types of products. Also product type isn't in my invoice table, should I add that to the table or can I join another table (Product) in check?
I guess this kind of validation / restriction is better fit to your application's business level rather then your data / database level
I'm trying to think of the most straightforward way to store quantities of an item in a database. I'm creating a database to work in conjunction with a web app I'm developing to monitor and log gear lent out to people. So, I've thought a few different ways already, though I'm not sure if they will be easy to maintain into the future.
Idea 1
I have a gear table that stores the types of gear (e.g. shirt, pants, hat) along with data like sizes etc. Then for each time gear is taken out, it is logged in the gear_inventory table, storing details such as user id, gear type and boolean to signify if it was returned and return date. Then to track quantities, we'll have total_quantiy and count of gear out for a specific gear item in the gear table, this being updated manual with a second query triggered when an item is taken out or returned to plus or minus the given quantity.
Idea 2
Have the aforementioned total quantity out linked to the gear_inventory as a count of all non-returned items of that type.
Idea 3
Have an update task to change these quantities on table update or insert. Then do the same by adding or subtracting the quantity of a given query.
Idea 1 would be the easiest but not as reliable as the others. Idea 2 being the most reliable the handling of quantities is entering on the database to ensure. Then Idea 3 not as reliable since it's still relying on a scheduled task to update it.
So, how would you implement a quantity amount to ensure it doesn't get out of sync with the logged inventory records?
Edit 1
More info - The core solution I am trying to achive is having a method of storing or having a count of items taken out which can be compared to a total nunber associates with that item. As suggeated below, it will act in a similar fashsion to a bowling alley's loaning/borrowing shoes, exect users will be logged. So a record will be inserted when an item is borrrowed, and that record will be updated with return date on return. The types of items will be in its own table to store details on a general item, and that will have a one to many relationship with the logged gear table. The problem is, what is a full proof/reliable way to store/retrieve number of items out. Or am I overthinking this and a simple count query would sufice, not sure how intensive count is when performed oved and over again.
Let's think about what we're keeping track of.
Information about kinds of items.
Current inventory.
Which item?
How many?
What's been loaned out.
To whom?
Which items?
How many?
What's been returned.
By whom?
Which items?
How many?
First cut might look something like this:
create table items (
id serial,
name text,
...
);
create table inventory (
id serial,
item integer references items(id),
quantity integer check(quantity >= 0)
);
create table loans (
id serial,
user integer references users(id),
item integer references items(id),
quantity integer check(quantity >= 0),
when_loaned timestamp not null default now(),
when_returned timestamp
);
When you loan something out, insert a row into loans. When its returned, set loans.when_returned. If loans.when_returned is null, it's still out.
You could decrement the inventory when items are loaned, and increment it when they're returned. To preserve data integrity this should be done as a trigger, not as a scheduled process.
Alternatively, don't change the inventory quantities. Instead, subtract the number of loaned items from the amount in inventory. That's select sum(quantity) from loans where item = ? and when_returned is null from select quantity from inventory where item = ?. This makes loans and returns simpler, and avoids the possibility of the inventory count being corrupted, but it might cost performance problems if there's many, many outstanding loans.
What happens if you loan out 5 items and they return 3? How do you track that? One simple option is to split a single loan into two loans.
-- Copy the loan row
insert into loans
select * from loans where id = :orig_id
-- Track that 3 were returned
update loans
set quantity = 3, returned = now()
where id = :orig_id
-- Two are now outstanding
update loans
set quantity = 2
where id = :new_id
Without knowing more about what you're using this for, what the use cases are, and what the scale is, that's about all I can say. It's a good starting point.
I'm thinking my table is going to get huge as days go by and more orders come in. Should I keep all orders in that same table forever or should I have a table for current orders and one for previous/finished orders since the current orders are the only ones that will be grabbed frequently?
If you keep separate table for previous/finished orders then when required you need to apply conditional joins or union.
according to me, rather than that, add one attribute say
(
...
...
IsArchived Bit
)
which is set to 0 (false) for current/latest order and 1 (true) for finished/previous orders, which will be faster than conditional joins or union at later on.
Maybe I'm not good in googling but I'm seeking for a set of gold rules and recommendations in designing databases related to billing.
Lets say I have an SQL table with transactions
transactions(id int, credit float, debit float, billable_account_id int)
Based on the rule of database normalization I abandon the idea of storing and updating on every transaction pre-calculated running balance for every *billable_account_id* in the same table or elsewhere regardless of the size of the transaction table.
I'm using Postgres if that matters(though the subject is common) and I'm not an SQL ninja at all but trying to be pedantic in designing.
Questions:
Am I right going with this approach?
If yes, what methods would you suggest in maintaining such table and in composing query for getting running totals?
Any references are very appreciated!
You can use analytic functions to generate a running total in most databases. In Oracle, something like
SELECT billable_account_id,
SUM( (CASE WHEN credit IS NOT NULL THEN credit
WHEN debit IS NOT NULL THEN -1 * debit
ELSE 0
END) ) OVER (PARTITION BY billable_account_id
ORDER BY transaction_date ) running_total
FROM transactions
If you don't have a TRANSACTION_DATE, you could use ID assuming that you can guarantee that the generated IDs are monotonically increasing.
However, from a performance standpoint, you are likely going to want to bend if not break the third normal form normalization rules for OLAP/ DSS type reporting because people are going to want to report on totals pretty frequently and some accounts are likely to have large numbers of transactions. You may, for example, want to create a separate table that has an ending balance for each BILLABLE_ACCOUNT_ID for each month end and then use the analytic function to just add the current month's transactions to last month's ending balance. In Oracle, you may want to create a materialized view that will automatically maintain the running total.