Database table design; link tables or rarely used foreign key? - database

My question relates to the best practices design of tables in a database for a specific scenario.
Say we have a Company that sells office equipment, Say Printers. This company also offers Service Contracts to Customers that have bought 1 or more of its Printers.
Given the above information, we can deduce three tables for our database:
Customer
Printer
ServiceContract
So for a given service contract, we specify which Customer the contract is created for and we assign 1 or more printers that comprise the contract agreement.
With regards to the Printers that are part of the service contract agreement, there are 2 ways we could approach the database design.
The first is to create a ServiceContractID column in the Printers table and create a basic Primary/Foreign key relationship between it and the ServiceContracts table. The only problem I see with with approach is that Printers don't have to be a part of a Service Contract and therefore you could have hundreds or even thousands of Printer records in the database, many of which are not part of a contract, so having this Foreign key column not being used for many of the records.
The second option is to create a link table which would contain 2 foreign keys referencing both The ServiceContracts table (It's primary key) and the Printers table (It's Primary Key). Combining both columns in this new table to make a unique composite primary key.
OK, here's my quandary. I don't see either option as being typically a Really bad idea, but I am stuck on knowing which of these 2 design decisions would be the best practise.
All comments welcome.

I think, without knowing your entire issue, that the second option is preferable. (i.e more properly normalized -in general)
The second option would allow some business rule flexibility which you may not have come up with yet (or your business model may change).
for example: dates may become important. The same ServiceContract may for instance be used even if the business decides on some rule, like all printers are covered for one year after purchase by this customer. where the same agreement just covers many purchases.
so option 2 gives you flexibility for adding other attributes on the relationship...

If I understand your problem domain correctly, the proper way to do this would be option 2. It sounds like a customer can have 0-many service contract, a service contract can have 0-many printers associated with it, and a printer can be associate with 0-1 service contracts (unless contracts expire and renew with a NEW contract, in which case the printer can have many-many.
Customers:
PK
CustomerInfo
Printers:
PK
PrinterInfo
FK on Customer PK
ServiceContracts:
PK
FK on Customer
// This creates a composite PK for the Contract_Printers Table:
Contract_Printers:
FK on Contract PK
FK on Printer PK
Hope that helps. I will be interested in hearing what others think . . .

Related

T-SQL - Using GUID's Across tables for storing common information?

I started building a database to manage things like vehicles, finances, bills, work history, residence history....etc.
I'm mostly doing this as a learning exercise to teach myself different methods of schema design and ground up development. I've been a database developer for 4 years, but I've only ever worked on the same system/schema. Even my ground up development of new features still have to abide by the existing Schema.
Anyways, I have tables for things like Vehicle Registration, Vehicle Loans/Purchases, Bills, etc. But rather than storing their billing info (payment amount, occurrence, etc), I thought maybe I could put a GUID column on every table, and then store the billing info by the GUID, and then have some sort of view or function that lets me look up the object_id (table) for a particular GUID.
Is this design method a good way to do things?
How would I go about designing the function/view to return the objectid / tablename for specific GUID's?
EDIT: I guess this is a poor explanation, so here's a quick example:
Table: VehicleRegistration
This table would have information like license plate, when the registration is good for, etc.
Table: VehicleLoan
This table would have loan information about each vehicle (amount financed, term, apr, date of purchase, etc).
Both of those tables would also have information like Billing Date, Occurence, Estimated Amount, etc. But instead of storing that data in the two tables, I would store it in another table called BillingInfo or something like that. Obviously I could add a FK on the two tables that point to the PK on the BillingInfo table. But that would mean every table that requires billing information would require that FK on it. Rather than creating that FK on every table...what if instead, every row in VehicleRegistration and VehicleLoan had a unique ID. And I would store the billing info by unique ID instead.
And since it's unque across tables, I would have a function or view to tell me which table that GUID is in. (keep in mind, this is a very small personal database, so for now, speed and optimization is not a concern).
If I applied this method to all common info, like billing information, then I could avoid having to put a FK on every table that needs it. I could just create the table and use the Unique ID's instead?

What's the proper way to associate different account types (database types) to payments and invoices?

I've run into a bit of a pickle during my development of a web application. I've boiled down the complexity of the application for sake of simplicity in this question.
The purpose of this web application is to sell insurance. Insurance can be purchased through an agent (Agency) or over the phone directly (Customer). Insurance policies can be paid through the agency or the customer can pay for the policy directly. So money is owed (invoiced) and received (payments) from multiple sources (Agencies/Customers).
Billing Options:
Agency (Agency collects from customer outside of app)
Customer
Here's where it gets complicated. Agencies are stored in a separate database table than customers (for obvious reasons). However, both agencies and customers need to be able to make payments and have invoices assigned to them. I'm having difficulty figuring out how to create the proper database schema to allow for both types of database records to be connected to their invoices and payments.
My initial plan was to set up separate relationship (joining) tables that link the agencies and customers to invoices/payments.
However, now that I've been thinking about the problem more, I think it might be beneficial to merge both agencies and customers into a single "Payee" table which would then be associated with payments/invoices. The payee table would only store a primary key. It would not contain actual names or info for the payee - instead I would pull that data via a JOIN with either the agencies or customers tables.
Regardless of whatever solution I choose I am still faced with the problem when creating a new payment record is that I need to scan both the agencies and customers table for possible payees. I'm wondering if there's a proper way to approach this from a database schema standpoint (or from an accounting/e-commerce standpoint).
What is the correct way to handle this type of situation? All ideas and possible solutions are most welcome!
Update 01:
After a few helpful suggestions (see below) I've come up with a possible solution that may solve this issue while keeping the data normalized.
The one thing about this method that rubs me the wrong way is that I will have to make multiple table selects to get a list of all the people who can potentially make payments and/or have invoices assigned to them.
Perhaps this is unavoidable though in this situation since indeed there are different "types" of people that can be associated with payments and invoices. I'm stuck with a situation where I have two different types of records that need to be associated to the same thing. In the above approach I'm using the FKs to link each table (Agencies/Customers) to a Payee record (the table that unifies both Agencies/Customers) and then ultimately links them to Payments and Invoices.
Is this the proper solution? Or is there something I've overlooked?
There are several options:
You might put this like you'd do it with OOP programming and inheritance.
There is one table Person which holds an uniqueID and a type (Agency, Customer, more in Future). Additionally you might add columns with meta-data like who inserted/when/why and columns for status/soft-delete/???
There are two tables Agency and Customer, both holding a PersonID as FK.
Your Payee is the Person
You might use a schema-bound VIEW with a UNION ALL to return both tables of your modell in one result. A unique index on this view should ensure, that you'll have a unique key, at least as combination of the table-source and the ID there.
You might use a middle table with the table-source and the ID there as unique Key and use this two-column-id in you payment process
For sure there are several more...
My best friend was the first option...
My suggestion would be: instead of Payees table - to have two linking tables:
PayeeInvoices {
Id, --PK
PayeeId,
PayeeType,
InvoiceId --FK to Invoices tabse
}
and
PayeePayments {
Id, --PK
PayeeId,
PayeeType,
PaymentId --FK to Payments table.
}.
PayeeType is an option of two: Customer or Agency. When creating a new payment record you can query PayeeInvoices by InvoiceId to get PayeeType and corresponding PayeeId, and then lookup the rest of the data in corresponding tables.
EDIT:
Having second thoughts now. Instead of two extra tables PayeeInvoices and PayeePayments, you can just have PayeeId and PayeeType columns right in Invocies and Payments tables, assuming that Invoice or Payment belongs only to one Payee (Customer or Agency). Both my solutions are not really normalized, though.

Best Table Relationship Design for Similar Entities

I am trying to figure out the best way to set up my Entity Diagram. I will explain based on the image below.
tblParentCustomer: This table stores information for our Primary Customers, which can either be a Business or Consumer.(They are identified using a lookup table tblCustomerType.)
tblChildCustomer: This table stores customers that are under the Primary Customer. The Primary Business customers can have Authorized Employees and Authorized Reps. The Primary Consumer customers can have Authorized Users. (They are identified using a lookup table tblCustomerType.)
tblChildAccountNumber: This table stores AccountNumbers for tblChildCustomer. These account numbers are mainly for the Child Business Customers. I may be adding Account Numbers for the Child Consumer customers, I am not sure yet, but I believe this design will allow for that if/when necessary.
Going back to tblParentCustomer : If this customer is a Consumer, I will need to add account numbers for them. My question is, do I create a 1 - Many relationship between tblParentCustomer and tblParentAccountNumber? This option would give me 2 different Account Number Tables.
Or would it make sense to create a Junction Account Table that intersects tblParentCustomer and tblChildCustomer?
The first option doesn't really make sense to me because what if there is only 1 Account number for a customer but multiple childCustomers?
Does it make sense to have 2 similar Account Tables that serve a different purpose?
Creating a many-to-many the way you want it to be, you need a link table that will make the whole thing go from 1-* and then *-1
That link table will have two FK, one linking to the parentTable and one linking to the childTable. Combination of those two FK will give you a composite PK (this is important to avoid duplicates). It will allow for any customer to be part of as many accounts as possible (duh.. it'll make the parent/child table a many-to-many relationship).
This approach is extremely common with regards to CRM or any Accounts containing people. Bring it one step further and in that table, you might want to add a "is primary contact" in the AccountMembers table. Drop the childAccountNumber table; you don't need it.

Three-way Referential Integrity - SQL Server 2008

I am building a database using SQL Server 2008 to store prices of securities that are traded on multiple markets.
For a given market, all the securities have the same holiday calendar. However, the holiday calendars are different from market to market.
I want the following four tables: Market, GoodBusinessDay, Security, and SecurityPriceHistory, and I want to enforce that SecurityPriceHistory does not have rows for business days when the market on which a security was traded was closed.
The fields in the tables are as follows:
Market: MarketID (PK), MarketName
GoodBusinessDay: MarketID (FK),
SettlementDate (the pair is the PK)
Security: SecurityID (PK), MarketID
(FK), SecurityName
SecurityPriceHistory: This is the
question - my preference is
SecurityID, SettlementDate,
SecurityPrice
How can I define the tables this way and guarantee that for every row in SecurityPriceHistory, there is a corresponding row in GoodBusinessDay?
If I added a column for MarketID to SecurityPriceHistory. I could see how I could do this with two foreign keys (one pointing back to Security and one pointing to GoodBusinessDay), but that doesn't seem like the right way to do it.
This model should do. The relationship between Market and BusinessDay is identifying, that is, a businessday does not exist outside the context of the market to which it belongs.
Similarly, the relationship between BusinessDay and SecurityPriceHistory is identifying, as it the relationship between Security and SecurityPriceHistory.
This means that the primary key of SecurityPriceHistory is composite: security_id,market_id and settlement_date.
This will enforce the constraint that each security may be have no more than one row in SecurityPriceHistory for a given market/business day. It does, however, allow for the same security to trade in multiple markets, despite the security's relationship to a particular market: to restrict that, the relationship between Market and Security needs to be identifying, thus:
SecurityPriceHistory could have a FK to GoodBusinessDay and NO FK to Market. You could figure out the market by joining to the GoodBusinessDay table. I don't really like this option, but it's a possibility.
You could also use a trigger to check and make sure that there's a proper GoodBusinessDay record on insert/update, otherwise reject the transaction.
I think you're going to need the marketID field in your securityPriceHistory table, assuming the same securityID could be sold in different markets on the same goodBusinessDay.
Setting it up the way you're thinking is fine. You have a parent, two related children, then a grandchild that has relationships with both children.
Even if a security can only be sold on one market, I'd still include the marketID in the securityPriceHistory table, with two compound FKs, MarketDay and MarketSecurity. Clearer that way, IMO.

How would you accommodate this requirement in EF4.0

I have a new circumstances (for me anyway) and wonder what is the best way to do this in EF4.0, (database first). This is a madeup example, but it mimics the logic of what I need to do:
Say you have just two tables PEOPLE and TEAMS, each team has a team leader and a backup team leader. The people table has a single record for each person, with a unique ID, the team record has a unique ID, but also a TeamLeaderID and a BackupTeamLeaderId, which map to the people table.
How do you handle this in EF? If I only had a teamleaderid, I could access it by Team.People.Name, but since I know have two links from teams->people this design will not work.
I can think of lots of kludgy scenarios for this, but what is the proper way to set this up in EF (or alternatively resdesign the underlying tables).
I'm not sure why you are starting with an EF question. Do you have your database schema worked out? If so, present that. If not, then I'd start there.
Your Team table will need a Leader foreign key to the People table. If any person can only be in one team, then you could add a TeamID column to your People table. Each person with TempID set to a particular Team would be a player on that team.

Resources