I need to create a database to manage a gas station.
I'm thinking of a basic product inventory and sales data model, but it need some changes.
See http://www.databaseanswers.org/data_models/inventory_and_sales/index.htm. This is how they proceed: the manager keep tracks of the inventory and sales twice a day, each time a gas pump attendant is in charge, and takes the responsibility of the sales.
How can I keep track of this ?
Using the Model that you provided you could use the first Model as reference:
And I would use all the six (6) tables namely:
1) Products
2) Product_Types
3) Product_In_Sales
4) Sales
5) Daily_Inventory_Level
6) Ref_Calendar
But I had to make some changes by alteration and adding:
First I need to include SalesPerson table that would have at least the following fields
1) SalesPersonID
2) Lastname
3) Firstname
4) Alias
In line with that I therefore need to add SalesPersonID as Foreign key in
my Sales table.
Now since you want to have twice a day Inventory then you could approach in many ways
you could add single primary key for Daily_Inventory_Level table or you could add a new field named Inventory_Daily_Flag which has either only the value of 1 or 2. If 1 that means that's the first inventory and if 2 that means that's the second inventory for the day. And that means by the way that you're Primary and Foreign Key at the same time would no longer be just Day_Date and ProductID but also Inventory_Daily_Flag for Daily_Inventory_Level table.
And also in line with that, that means you need to also to add a field in your Product_In_Sales like FlagForInventory with Boolean as Data Type.
So, let's say a Supervisor came in to do the first inventory, then the products sold
in Product_In_Sales for the day would be flag as True for the FlagForInventory and
then would be transferred to Daily_Inventory_Levels with Inventory_Daily_Flag field
as 1 to indicate as the first inventory and of course the Level also would be updated.
And so when the days end and the 2nd inventory is to be executed then those
sales for the day from Product_In_Sales table whose FlagForInventory is false then
it would be flag as True for FlagForInventory and then transferred again to Daily_Inventory_Levels with Inventory_Daily_Flag as 2 indicating the second inventory.
And of course you need to update the Level as well.
Does it make sense? If not I could always change the approach? ;-)
Related
I have analyzed my as below and I have two point I am confused about
1- currently when I insert an items within orders I give order_ID as a PK
so each item within the order as its own PK... and same customer_id (FK) for all Item within the order so ... in that case the invoice number is same as the customer_ID
Is that what should think goes on or there is something wrong with this work flow ?
2-in some cases I don't need to record the customer information I just want to
insert the orders without their customer info.. I don't have clear idea about how think should happen :S
3- IF I want to apply a discount on some customer orders where the discount should I allow user to able to apply on the item per orders level ?
or on the whole order ? and where the discount column should be stored
1 - This design seems fine for the problem. You are stating that for every product ordered, this is the customer line. You can pick the ID, name, tax/fiscal number, address, etc.
2 - If you don't need any kind of customer information, make the customer_id on the Orders table accept NULL. It is the cleanest way to do it.
If for some reason NULLs are not an option or you want to keep on the database some basic anonymous customer data, you can create a line on customers for anonymous users (Ex.: ID: 1 / Name: ANONYMOUS ...) and place that ID on the order line.
3 - Placing the discount per product ordered might be the better idea.
If you want to apply a discount for the complete order, you just need to place that discount on every single order line.
If you want to apply a discount for a single product, you just need to place that discount on that product line.
If you want to apply a discount for a single product with a limited ammount of quantity (Ex.: Discount of 50% but limited to 1 purchase), and the customers buys more than that limit, you just need to place 2 orders for the same product. One with the discount and max quantity and the other without discount and the rest of the quantity.
Placing this on the order level wouldn't work for single product discounts.
This were answers to your questions. I would also question your design in points like:
If the customer changes address, is your order supposed to change too? If not, you should use the normal approach for orders, which is to have a order header table, with fixed information, like the address and the foreign key to the customer, and a order line table, like your orders line, but with a foreign key to the order header. That also avoids repetition.
Are you expecting up to 2 phone numbers? If you do, the design is ok. If you don't know how many phone numbers to expect, maybe a table with phone numbers, with foreign keys to the customer might be a better approach.
I have a table Salary with a column PersonalId and a table Person with a column Name.
In the first table salary data will saved with a PersonalId which relates it to the Person table. In salary bill all data will gather together and Person name will be referenced from Person table.
After 1 year a specific person name will change from Michael to Maic. Now I want the last year salaries bill remain with previous person name Michael and the new salaries bill generate by new name Maic.
How we can do that?
It could depend on what type of operation you need to to most and on how much people change their name, because the number of joins you may need to make could vary a lot.
keep a field in Person that points to the next Person which is a change of name
keep another key in Person that varies only for the physical person
keep a limited number of names in Person that someone could dispose of, with an index of the current name
in another table you keep the relations between the various name of the Person
It could depend on what rules of normalization you follow, for now I'm not thinking about that.
Anyway, with the first case you don't need to change Salary, but to reconstruct the identity of a Person you need multiple requests or at least a stored procedure.
In the second case you still don't need to change Salary because you add a field to Person, but to get all the Salary entries for that physical person you'll need some work, again probably a stored procedure to get the added field and then something that joins all the Salary entries.
The third maybe is the simplest, but also the limited one, and you need in Salary another field that tells the index of the name to use in that entry.
The last case gives you a stable identity, but it may need some work because of the added table, and still there are multiple implementations. You could have salary reference that table instead of Person, or you could consult that table only when you need all the data, but you cannot reference its primary key from Salary because it would not permit to discriminate the name.
Lunadir's right in a certain way -- but all of those approaches are complex, and of rather great difficulty.
The other way -- simpler, and perhaps more correct & robust -- is to keep NAME and PAID_DATE columns in Salary or SalaryPaid, and write the actual name & date paid at the time the payment is made.
Good old batch-processing style -- and it has the benefit of actually capturing the key financial facts, of what payment was made & what name it was made to, which are the actual auditable transaction history.
Do you pay each Salary entry individually, or in bunch (PaySlip or SalaryPaid)? Put the NAME column wherever you record the actual payment & timestamp it occurred.
I am wondering if it is okay to have master and detail table for employees?
As per requirments, data can filtered by department by country and by employee code on report level.
If employee's department or country code is changed then the changes will go in detail table and old record will be set to IS_ACTIVE = 'T'.
---------------------Master Table--------------------------------------
**EMPLOYEE_CODE** VARCHAR2(20 BYTE) NOT NULL,
EMAIL VARCHAR2(100 BYTE)
FIRST_NAME VARCHAR2(50 BYTE)
LAST_NAME VARCHAR2(50 BYTE)
WORKING_HOURS NUMBER
---------------------Detail Table--------------------------------------
**PK_USER_DETAIL_ID** NUMBER,
FK_EMPLOYEE_CODE VARCHAR2(20 BYTE),
FK_GROUP NUMBER,
FK_DEPARTMENT_CODE NUMBER,
FK_EMPLOYER_COUNTRY_CODE VARCHAR2(5 BYTE),
FK_MANAGER_ID VARCHAR2(20 BYTE),
FK_ROLE_CODE VARCHAR2(6 BYTE),
START_DATE DATE,
END_DATE DATE,
IS_ACTIVE VARCHAR2(1 BYTE),
INACTIVE_DATE DATE
Employee table will be linked with Timesheet table and for timesheet reports data can be filtered by department, country and by employee code.
OPTION : I
Have one employee table with one Primary Key and create a new entry whenever department or role is updated for an employee.
Add country and department code in the timesheet table.
--> This way i don't need to search employee table.
OPTION : II
Have master and detail table.
Add country and department code in timesheet table.
--> This way i don't need to search employee table plus i will have master detail table
OPTION : NEW
Have master and detail table.
Timesheet table will have EmpCode.
If user move to new location or change department then Insert a new row in the detail table with the new dept Code and same Emp No.
Update an old row and set the End Date field so if he changes his location or department then the End Date field needs to be updated.
Which one is a best option and is there any other better option available?
This is one way of implementing this requirement, and it's an approach many people take. However, it has on emajor drawback: every time you query the current employee status you need to filter the details on start and end date. This may seem like a trivial thing, but you wouldn't believe how much confusion it can cause, and it has performance implications too.
These things matter, because most of the time you will want only the current details, with queries on history being a relatively rare occurence. Consequently you are hampering the implementation of your most common use case to make it easier to implement a less-used one. (Of course I am making assumptions about your business requirements, and perhaps yours is not a run-of-the-mill employee application...)
The better solution would be to have two tables, an EMPLOYEES table with all the detail columns too and an EMPLOYEES_HISTORY table with the same columns plus the start and end date. When you change an employee's record insert a copy of the old record in the History table, probably by a trigger. Your standard processes have just the one table to query, and your history needs are met fully.
By the way, your proposed data model is wrong. Working_hours, email_address and last_name are definitely things which can change and perhaps even first name (e.g. through changes in personal circumstances such as getting married). So all those columns should be held in your details name
Option 3 - Please note that this option is useful only for the reports Point of View.
Whenever you insert the data, create a De-Normalized entry in a new table.
Whenever an entry will be updated, the De-Normalized entry will be updated in the new table.
The New Table will have all De-Normalized columns of Employee.
So while Performing the search, this will benefit you as the results will be calculated without using Joins. Thus, the access time will be reduced.
Records in the new table will be Created/Updated in The Insert/Update Trigger.
Improvements in Option - 2 and Option 1
Don't create redundancy by adding duplicate columns.
I'm currently creating a stock management system that uses multiple warehouses (with sub locations) and since this is my first big project I would love some feedback.
Let me show you what I have done so far...
Link as Im still new here
You first need to create a Warehouse, then you can create a Location within that Warehouse.
You can also create an ItemType (ItemGroup), then you can create an Item for that group.
Once you have an Item and Location you can add Stock, the Stock table has a composite key so that duplicates cant be added. I also added a constraint so that you could not enter an Item of the wrong ItemType, same constraint on the Warehouses/Location.
I then need to keep records of each piece of stock, SerialisedItems and NonSerialisedItems. Example: If non serialised stock is added with a quantity of 10 then I currently create 10 rows inside the NonSerialisedItems table (1) that are set to ‘in stock’ with the relevant stock information. If they change the amount of stock then rows would be deleted or added (2).
I could also do with a Van table somewhere that is similar to Warehouse, but think I would have to change the Warehouse table to something like Storage that references two tables, Warehouse and Van?
(1) I currently have a TransactionScope on my page adding x number of rows, Is this the best way to handle that?
(2) The Quantity amount in the Stock table would have to count the number of rows for that item and then update the Quantity each time stock is added or removed, any problems here? - Both Questions Fixed - Only create rows for serialised items.
Any other problems?
Well that’s what I have done, if its good or terrible let me know.
Also if there are any pitfalls I should be looking out for that would also be great to know.
Thanks
[EDIT]
Thanks to Neville K I have made a few changes...
Link to new and improved database
This seems to make a lot more sense! Think I had been staring at it to long yesterday!
Firstly, this is pretty much a solved problem - the best resource I know of is the "data model resource book" series; there's a very flexible model for stock maintenance apps in there.
Secondly, your design is not very normalized, and relies on a lot of duplication. Not sure what the reasoning is, but usually, the "stock" table would have a link to "item", but not "itemType" - the fact that an item belongs to an item type is already captured in the relationship between item and item type, and you don't need to duplicate it. The same goes for location and warehouse.
The key change I'd suggest is the concept of a stock transaction, rather than a single "stock" table.
Something along the lines of
TransactionID date itemID locationID quantity
------------------------------------------------------------------
1 1/1/12 1 1 10
2 1/2/12 1 1 -1
3 1/3/12 1 1 20
To find out the current stock for an item, you sum(quantity) group by item; to find the current stock for an item broken down by location, you sum(quantity) group by item, location.
On the first of Jan, there were 10 items in stock; on the second, 1 item was removed, leaving a stock of 9; on the 3rd, 20 new items came into stock, giving a balance of 29.
This design allows you to track change over time, which is a common requirement; it also provides an audit trail by creating transaction meta data (operatorID, invoice number etc.).
I need a table that stores items and tracks when an item is...
queued
marked for shipping
shipped
marked for return
returned
The table also needs to tell me how many items a customer...
has received in a month
has at home at this time
I tried using inheritance. I assigned each step a typeId (from 1 to 5, each id representing the current step in the workflow). This approach is not ideal because updating a workflow step erases history.
For example, if an item moves from shipped (typeId 3) to returned (typeId 5) we lose an accurate count for shipped items.
How should I approach this? Also, I prefer to keep the data in one table unless I get a compelling reason not to.
Update
Items are mailed to customers incrementally. There are limits to how many items a customer can receive within a month period, and limits on how many items a customer can have at home at any given time. For this example, let's assume 4 for earlier and 2 for the latter. A customers queue can have any number of items. For this reason, items in the queue need to be ranked so the order of items sent can be according to the customers preference.
Items that have shipped already will need to fall out of ranking (the customer can no longer modify rank after an item is sent).
No inheritance here. Time fields are actually date-time. A row is entered into the Tracking table when a customer adds an item to the queue. Other time columns from TimeMarkedShip to TimeReturned are NULL until the action happens. The TimeQueued is part of the primary key in order to allow a customer to rent an item more than once (sounds like video rentals to me).
To count items that a customer has at home you could use something like
select count(1)
from Tracking
where CustomerID = 1755
and TimeShipped is not NULL
and TimeReturned is NULL ;
Rather than a typeID for the current step, it looks like you need a boolean column for each step. Then when you want to count the "net shipped" items, you can subtract the "returned" items from the "shipped" items.
In addition, if you want to track the history, you could make each of these steps a nullable date field, so that you can see that an item was shipped on 3/5/11 and returned on 4/1/11. This may help if you're using this table in other ways, such as managing your shipping/receiving or billing. A NULL, of course, would indicate that the step has not been performed (yet).