Key Manager Database Design - sql-server-2005

My task is to add some functionality to an existing web application using SQL Server.
My client's business provides a service where keys are issued to employees who then go to the various locations to perform the requested work. She wants to keep track of who has what keys for their clients. They have about 100-125 clients and 6 employees. She will be the only person using the web gui for the issuance and returning of keys.
For inspiration, I went to Google and found a demo program called KEY ORGANIZER which runs on the desktop. It does exactly what my client is looking for but is a desktop app, not a web app. So, I figured I’d just reverse engineer it and tailor it for my client’s needs. The desktop application does way more than my client needs. Here is a high level overview of what she is looking for:
Issuing of Keys:
She clicks on the key image next her customer’s name. Let’s say she has 3 keys for the customer but all 3 are already checked out to employees. She would receive an alert of some kind stating there are no keys available to issue but would still allow her to issue a key in situations were inventory is off (so the database needs to be able to handle negative values). If there is a key available, then proceed to the next bullet.
In the next window, she is presented with a form. (list of employees name to choose from and today's date).
She selects the employee from the drop down list and clicks the OK button and the modal window closes.
A log entry is entered for every check-out/check-in and an email will be sent to the employee upon each check-in and check-out.
Returning of Keys:
She would also like to be able to select a button next to an client’s name to see which employees currently has a key and be able to select an employee’s name to return a key.
Similarly, my client would like to click on the employee’s name to see if a list of keys in their possession and be able to return a key from the list, too.
A log entry is entered for every check-out/check-in and an email will be sent to the employee upon each check-in and check-out.
I do not need help with the coding of the web page. I just need some guidance on how to properly setup the database tables (e.g. should the key inventory field be a part of an existing table or a different table for example) to best handle the revolving key inventory scenario.
Here are the tables I’ve come up with:
Customer_tbl (existing table)
• CustomerID
• KeyQTY (new field?)
• KeyLabel (new field?)
Employee_tbl (existing table)
• EmployeeID
• Fn
• Ln
KeyJournal_tbl (new table)
• JournalID
• ActionDate
• ActionPerformedID (key issue, key returned, key lost, etc)
• CustomerID
• EmployeeID
• Inventory (the total number of keys received from the customer – or should this be under Customer_tbl?)
• IssueReturnDate
KeyInventory_tbl (new table)
• KeyID
• CustomerID
• KeyTotal
NOTE: I added the SQL Server 2005 tag only for reference. I don't need help with the SQL statements in case that tag is misleading.

My inclination would be something pretty close to yours. Here:
Customer
customer_id
name, address, etc, whatever reference info you need
Employee
employee_id
name, etc
KeyInventory
key_id
description
customer_id
qty
KeyCheckout
employee_id
key_id
checkout_date
return_date
Notes:
I put a description on KeyInventory because I'm assuming you could have more than one key for a customer and you need to distinguish them, like "Apt 1" and "Apt 2", or "Warehouse" and "Office".
When an employee is given a key, create a KeyCheckout record with the date it was given. When the key is returned, fill in the return date. If the return date is null the key is still out.
To find which employees have keys for customer #cx:
select employee_id
from KeyCheckout c
join KeyInventory i on i.key_id = c.key_id
where i.customer_id = #cx
and c.return_date is null
To find how many of key #kx are still available:
select i.qty - count(c.employee_id)
from KeyInventory i
join KeyCheckout c on c.key_id=i.key_id and c.return_date is not null
where i.key_id = #kx
Etc.
You'd definitely want an index on return_date, or maybe KeyCheckout(key_id,return_date) and KeyCheckout(employee_id,return_date), because this table will grow quite large and without an index queries will get unbearably slow.
I think your Journal table is a similar concept to my Checkout. I'm just putting the checkout and return fields in one record to make it easier to determine if a key is still out. With separate records for in and out, you have to match them up, which is a pain.
Don't put the qty into a journal-type record. That's not an attribute of the "transaction", it's an attribute of the key itself. It belongs in the inventory table.
Don't put the key qty in the customer record. If you need to know how many different keys a customer has, just do select count(*) from keyinventory where customer_id=#cx. Storing this count in the customer record just creates the possibility that it won't match the actual number of key records.
I'm not sure what "keylabel" is. If that's a description of the key, it belongs in the KeyInventory record, because a customer could have more than one key. I don't think it makes sense to say that a customer can have only one key. Even if that happens to be true of your customers today, it seems likely that a customer could have multiple keys in the future, might as well allow for it.
I think your inventory is non-serialized, i.e. 3 keys for the same lock are not distinguished from each other, it's just "quantity 3", right? If they have individual serial numbers on them or something, then there would be no quantity field and you'd have individual records for each key.

Related

SQL DB structure - Draft orders and consideration of Order ID as identifier

I am upgrading a system for a client which was developed by myself around 10 years ago.
It is a standard (if there can be such a thing, of course) sales / inventory / accounting system.
One of the additions they have asked me about was the ability to create draft orders. As the company has grown, so have the sizes of the orders. They want the ability to begin entering an order for a client and have the option of saving and coming back to it later.
My initial thoughts would be to have an orders table which includes drafts and a field which signified the status (draft / posted). This would prevent duplicating data across an Orders table and a DraftOrders table.
This seems correct to me but of course the OrderId field (auto-increment int) would no longer be a solid identifier for the Order (since a lot of the numbers in between orders may be missing).
The client would ideally like to keep the OrderId as an identifier so is there any solution which would enable this, rather than creating a draft order table?
Many thanks in advance for your help.
Kind regards
If you are to ensure that the identifier has no gaps for taxation purposes, you can not use the PK in the first place. This is because the sequence may have gaps, too. For example, if an INSERT fails due to some constraint violation you lose the reserved sequence number.
In case you do not want to create a separate table, I may suggest adding a new column to store the tax order ID. It will remain NULL for drafts and will be filled programmatically when the order is placed. On the UI you will show this new column and will possibly allow some searching on it (hint: good candidate for an index), yet internally you will still use same FKs as before (for both orders and drafts).

How can I use forms in libreoffice base to add/modify data in a many-to-many relationship?

I am essentially trying to create a glorified contacts list using LibreOffice Base. Many of our contacts have multiple addresses (office, mailing, home), and sometimes multiple people have the same address.
I've created a simple contacts table with the Contact ID, Last Name, and First Name. I've created an address table with an Address ID, City, State, etc. I've also created a junction table with Contact ID and Address ID, and connected the three tables using the relationships tool.
Now I want to add everything into a single form. I watched this youtube video, which was very helpful, but I want to be able to add new cities instead of only selecting from a pre-established list. So I followed along with the video, but set the columns to "combo box" instead of "list box." However, when I try that I get an error message:
Error inserting the new record
SQL Status: 23000
Error code: -177
Integrity constraint violation - no parent SYS_FK_94 table: Address Table in statement [INSERT INTO "Contact-Address Junction" ( "Address ID","Contact ID") VALUES ( ?,?)]
I assume there's something obvious that I'm missing, but at this point I'm pretty stuck.
E: I took more screenshots to show the relationships, tables, and how things connect in the form:
In the video you cite, this is kind of silly as there is no need for a many to many relationship. The author could have simply added a Movie ID field to the genre Table, (so multiple genre records can point to each movie record).
I have a complex many-to-many contacts structure that I'm in the process of porting from MS Access to LibreOffice. It has 4 primary data tables: Groups, Address, Phones, and People. And there are 6 link tables to connect those primary tables: GroupAddress, GroupPhone, GroupPerson; AddressPhone, AddressPerson; and finaly PhonePerson. Unlike the video you cite above with only 2 fields, in my link tables there are 3 fields. GroupAddress for example has GroupAddressID (the unique id for the link table itself), GroupID (which points to the Groups table), and AddressID (which points to the addresses table). This allows any number of addresses per each group, and at the same time, any number of groups per each address.
So the whole thing has maximum data flexibility: For example it allows for unlimited number of people per group, each person can have an unlimited number of phones or addresses, each address an unlimited number of people, etc.
Implementing it in LO: Because in LO you can't edit a query based on more than one table (you can view it, but not edit it), like you can in Access, (and therefore you also can't build a form with a table that can edit a query based on more than one table), in LO this is not as clean as it is in Access.
In Access it works very well and the link tables manage themselves! In LO you have to manually edit the link tables in a separate table. I'm starting to think about how I might use some macros to improve on this, but for the moment it's bare bones.
To give you a better idea, the first form to edit Groups, which also edits the group's addresses, people, and phones (not just those tables, but also the links to those tables) looks like this:
Group lookup pulldown (used to find a group record)
(this is a drop down box with custom code that helps me find group records)
Group editing fields, e.g. Group name, category, url, etc
Then below that
Group-Person links table
Then to the right of that
Persons table (plural) - to create new person, then..
And below that
Person table (singular)
[pointed to by Group-Person link]
to view person pointed to.
Group-Address links || (similar structure to above)
(for example, when a business has two or more addresses)
Group-Phone links || (similar structure to above)
(this is for phone#'s that the group owns directly, not personal phones of the group's members, and not phones tied to specific addresses).
----------
Then there are 3 other similar forms,
one for Addresses w/ Person, Group & Phone links;
one for Phones w/ Group, Address & Person links;
and one for People w/ Group, Address and phone links;
Here is a screen shot of the first of the 4 editing forms, to edit the groups and the links associated with the group:
Hope this helps. I would be interested to see what you develop. Thanks.

How can I duplicate patient information in Microsoft Access?

I am working for a hospital building a patient recording system on Microsoft Access.
One of the Doctor's requests is that when they are seeing patients that are siblings, is there any way that they do not have to type in duplicate information for these relatives? (Address, phone number, town of residence, etc...)
I understand that the ID number will change for each patient. Say the form goes like this:
1) Does patient have other siblings at risk? (Y/N)
2) If so, how many?
Depending on the digit that answers question two, could I duplicate the primary patient's information so that it exists in 3 different files? The doctor is adamant that it would be easier to go back and alter a few fields than it would be to type them repetitively.
Is this possible? Are there any shortcuts to doing so?
It sounds like you need a table called RESIDENCES, which would have an id, address, phone number etc. A patient record would include a foreign key to this table's id. When a sibling is added, the sibling record would include the same foreign key. The tricky part of doing this would be in the user interface: when a new patient is about to be added, you will have to ask whether this patient is a sibling of someone. If yes, you will have to ask who the sibling is, then copy the 'residences' foreign key; if no, you will have to display a dialog which allows the 'residencies' data to be added.
But what happens if a sibling changes address or has a separate telephone number? In that case, the contact details of each person would be stored in the patient record, without a 'residences' table; your user interface could include a function which copies contact data from record to record.
I think that this approach is better because each person has his own contact data which is independent from everyone else. The problem which you stated is more an interface problem (how do I add this functionality to make things easier for the users?) than a data modelling problem (how should the data be stored?).

Insert into statement

I have a table
Moon PIS
pID pAddr cID cName leaseExp mRent oID oName oContact
pID – property id: coded to identify the specific property, chosen to be primary key.
pAddr – property address, required (ie, cannot be null)
cID – client id: coded to identify the client – null means not rented out yet
cName – client name – null means not rented out yet
leaseExp – lease Expiration date – null allowed, if not rented out yet.
mRent – monthly rent (in dollars) – null allowed.
oID – owner id: coded to identify the property owner, required (ie, cannot be null)
oName – owner name, required (ie, cannot be null)
oContact – owner’s contact address.
and I am suppose to normalize this table
I created a table for the property, owner, and client.
The property table has pID, pAddr
the client table has cID, cName the owner table has oID, oName, oContact
first, I was wondering if normalized the table properly?
if so I am then required to move the data from the MoonPIS table into the newly created tables. I have attempted:
INSERT INTO Property (PropertyID, PropertyAddr)
SELECT pID, pAddr FROM Moon PIS
I am receiving an error saying "Microsoft Access database engine could not find the input table or query 'Moon'. Make sure it exist and that its name is spelled correctly."
Do I have to set up relationships prior to transferring the data. All I have done is created the tables and columns.
You need to escape the name because it contains a space:
INSERT INTO Property (PropertyID, PropertyAddr)
SELECT pID, pAddr
FROM [Moon PIS];
This answer isn't valid for the question, as it refers to the original table, and not to the changes suggested in the question... but I'll leave it for now as I think it might be useful anyway, if someone disagrees I'll remove it.
first, I was wondering if normalized the table properly?
No, it's not properly normalized as it records data for multiple types of entites (properties, clients and owners). You'll want to move the client details (cName) and the owner details (oName and oContact) to their own tables (Client and Owner maybe) and just keep the cId and oID as foreign keys.
Also, what is this table supposed to record, right now you include a lot of data that doesn't depend on the primary key (propertyId). Take rent for example, is the rent bound to a property or is it something that relates to a specific contract with a client and can change depending on client? If so, it doesn't belong in the property table. And so on...
Normalizing relational designs can be hard (and involve formal logic), but if you want your design to work, it's a subject well worth putting some time into studying.
As for the query error, don't use white spaces in table names :)

Same form that submits to two different tables

I am quite new to Microsoft Access but i have been working with databases for quite a while now, so I understand "the back end" (so to speak) as to how I will set up this database, but I'm not sure how to tell Access what to do and how to do it.
The aim of my database is to load up a customer's account with their information; eg, phone number address, email, etc. All this information has been migrated to a table within my new database project.
from here I would like to create a separate table which has notes which can be assigned to each user's account number. the aim of this is to be able to read up on recent activity of these customers and be able to search and filter that information on an easy to use front end interface.
So so far I have two tables, one with the customer's information in it and another which is where I would like to save the notes for each customer.
the primary key which I will be using is the customer's account numbers. This, of course, being unique to each customer and would be perfect for the primary key in both of these tables.
I have set up a relationship between both of the tables as they will both contain the user's account numbers.
I'm just not sure how to go about it and would really appreciate the help. I am currently using Microsoft Access 2007.
for your second table you need to use a new primary key like "customerInformationID". Reference the customer table by a foreign key.
Then you can join these tables like this:
SELECT c.Name, c.Number, ci.notes
FROM customer AS c
INNER JOIN customerInformation AS ci ON c.customerID = ci.customerID
Why do you need two tables anyways? If you don't need them for a technical purpose like "every user shall be able to store his own notes to a customer" then you can also store them in your main table as all of these information are only dependent from the primary key.
Best Regards
Bruellhusten