One to One with constraint and inheritence - sql

I have been questioning a certain scenario if it could benefit from using a one to one relationship in my ERD. I have a table called library with a FK called typeID from a table called element type. Essentially the element types have a sibling relationship with element as the parent and each item in the library is one of those types. The library is mainly used to create a hierarchy amongst the elements and other properties of how they exist in the library. If I add a column for every property of each type of element most columns would be virtually empty because not every element type has every property of the others. Also there are some other tables that are using the library items id where I want to put a constraint on what types of elements can be a foreign key for that table because not every element type can have that relationship. I was wondering if it is a good idea to use 1 to 1 where there is that same constraint on what type of element from the library can exist in the table, then add the unique properties. For example tableXYZ can only have items where typeID from library = 1 and all the 1 types are always in it. It seems like a good way to simulate object inheritance/generalization. Also all the tables connecting to library needing a specific type of element for the FK relationship could connect to the extended 1 to 1 table which already has that constraint so they don't have to. Also some of the elements are extensions of each other, could you have 1 to 1 then extend 1 to 1 again? Is this a legit idea? Will it even work? Is there anything I am not seeing here?
fyi the DB is postgreSQL

You might want to look into two techniques: class-table-inheritance and shared-primary-key
By applying these two techniques to your case, you may end up with a simpler, yet more powerful design than the one you propose. In some cases, you can dispense with the TypeID entirely, because a join between the generalized table and the appropriate specialized table will yield precisely the objects you are looking for. In addition, because the join is on two primary keys, the join will be relatively fast.

Related

Table with foreign key that can reference different tables

I'm trying to build a table for an inbox app that stores its messages within inbox table.
The structure of the table is as follows:
inbox_id|sender_id|receiver_id|subject|message
The columns sender_id and receiver_id are FOREIGN KEYS and can reference multiple tables.
There are currently 3 types of users within the database and they all can send messages to each other. A user of type UserType1 can send a message to UserType2 and vice versa, or UserType1 can send messages to UserType1. So receiver and sender can reference one of these 3 tables.
My solution to this problem is to build a inbox_user table containing columns for each user type and to have sender_id and inbox_user reference it.
My main concern is limited flexibility of the solution and wasteful usage of resources. I would, at all times, always have 2 empty columns per row. And that would become even worse if I introduced more user types.
Would this be considered a bad practice? What are some more flexible and intelligent designs?
From your description it sounds like the best practice should be applied to your user table and not this inbox table. Of course, I don't know your constraints, but if you have 2 or 3 types of users with each type of user in its own table, that is a poor design (again, not knowing your constraints). The preference is to store all users in one table with a column to indicate their type. Then the reference to your inbox table becomes straightforward with both sender and receiver FKs pointing back to the same user table.
Otherwise, you're going to end up using multiple columns to reference each table like you said (UserTypeASenderID, UserTypeBSenderID, UserTypeCSenderID, etc). My preference is to have null FK columns and gain the referential integrity than to implement some other solution and lose the constraints.
3 different types of users is a classic type/subtype situation. (or, if you prefer, class/subclass). There are several ways to design for a class/subclass situation. Two that look good to me are "Class Table Inheritance" and "Single Table Inheritance" as explained by Martin fowler. You can find a synopsis online. You can also visit tags by these names in here, read up on the info presented, and look at the tagged questions.
Single table inheritance suffers from a lot of NULLs for fields that are not applicable some of the time, as you pointed out in the Q. This may or may not be a problem for you, depending on your case.
Class table inheritance involves a little programming when a new entry is made in a subclass (subtype). It also involves more joining, but it isn't very expensive joining. Class table inheritance is frequently combined with a technique called shared primary key. In this technique, the subclass tables end up with a primary key that is a duplicate of the primary key in the superclass table. It's also a foreign key to the superclass table. This makes joining subclass data and superclass data simple, easy, and fast.
Shared primary key resolves the quandary you stated in your Q, namely how to reference more than one table with one foreign key. A foreign key reference in some other table to the superclass table will also be a reference to at least one of the subclass tables. This seems like magic. Try it, see if you like it.

How do I structure a generic item that can have a relationship with different tables?

In my example, I have a watch, which is an indication a user wants notifications about events on a different item, say a group and an organization.
I see two ways to do this:
Have a groupwatch resource, with a groupwatch table, with id,user,group (group FK to group resource and table); and a orgwatch resource, with a orgwatch table, with id,user,organization (org FK to organization resource and table)
Have a generic watch resource, with a watch table, with id,user,type,typeid. type is one of group or organization, and typeid is the ID of the group or organization being watched.
Since both of them are watches, it seems a waste to have two different tables and resources to watch 2 different objects. It gets worse if I start watching 4, 5, 6, 20, 50 different types of resources.
On the other hand, a foreign key relationship appears impossible if I just have a generic typeid, which means that my database (if relational) and my framework (activerecord or anything else) cannot enforce it correctly.
How do I best implement this type of "association to different types of record/table for each record in my table"?
UPDATE:
Are my only choices for doing this:
separate tables/resources for each watch type, which enables the database to enforce relational integrity and do joins
single table for all watches, but I will have to enforce relational integrity and do joins at the app level?
If you add a new type of resource once every six months, you may want to define your tables in such a way that adding new resources involves changing data definitions. If you add a new resource type every week, you may want to make your data definitions stay the same when you add new types. There's a downside to either choice.
If you do choose to define table in such a way that the types are visible in the table structure, there are two patterns often used with type/subtype (aka class/subclass) situations.
One pattern has been called "single table inheritance". Put data about all the types in a single table, and leave some columns NULL wherever they do not apply.
Another pattern has been called "class table inheritance". Define one table for the superclass, with all the data that is common to all the types. Then define tables for each subtype (subclass) to contain class specific data. Make the primary key of the subtype tables a duplicate of the primary key in the supertype table, and also declare it as a foreign key that references the primary key of the supertype table. It's going to be up to the app, at insert time, to replicate the value of the primary key in the supertype table over in the subtype table.
I like Fowlers' treatment of these two patterns.
http://martinfowler.com/eaaCatalog/classTableInheritance.html
http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
This matter of sharing primary keys has a few beneficial effects.
First, it enforces the one-to-one nature of the ISa relationships.
Second, it makes it easy to find out whether a given entry belongs to a desired subtype, by just joining with the subtype table. You don't really need an extra type field.
Third, it speeds up the joins, because of the index that gets built when you declare a primary key.
If you want a structure that can adapt to new attributes without changing data definitions, you can look into E-A-V design. Be careful, though. Sometimes this results in data that is nearly impossible to use, because the logical structure is so obscure. I usually think of E-A-V as an anti-pattern for this reason, although there are some who really like the results they get from it.

Table which contains parent_id in same table while using a foreign key

I have a table which will contain various categories. The following is a minified table structure:
tb_categories
category_id
category_name
category_parent_id
I created a foreign key constraint on category_parent_id on the category_id so data integrity can be held within the same table.
First question is, is it good practice to have a foreign key on the same table. From my way of thinking I am thinking that yes in such a case, it is a good practice.
Second question is, what is the best approach on how to store the global parent entity?
I came up with the following methods:
Method 1: category_parent_id can store nulls and the only null is the global parent category entitled All
Method 2: category_parent_id cannot store nulls and the global parrent ALL will contain its same category_id. Therefore, for only this category, both category_id and category_parent_id will be identical. Without nulls, I cannot insert this category_parent_id as 0 since 0 does not exist as a category_id
Method 3: Not having a global parent and there will be different 'parents'. For example, having Audio, Visual as parents and MP3, WMA as Audio's children and MPEG, AVI as Visual's children. Throughout this method, the same principles of methods 1 and 2 applies.
Method 4: This is the least method which I prefer which includes in not having this foreign key constraint and thus the global parent can be set to 0 which does not exist in any other category.
Any suggestions? As I am looking for the best practice and not something that 'just works'.
It is normal to have a table refer itself. There are a lot of real world scenarios that need this situation (Employee -> Manager is a famous textbook example).
And, you will end up having a "global" parent whether it is a single global parent or multiple global parents. So you need to come up with an approach.
I prefer method 1 - an element without a parent will have no parent at all, because, well, it exactly realizes your business rule.
Having a 0 or referring self as parent will create problems when you have complex queries

How to model a mutually exclusive relationship in SQL Server

I have to add functionality to an existing application and I've run into a data situation that I'm not sure how to model. I am being restricted to the creation of new tables and code. If I need to alter the existing structure I think my client may reject the proposal.. although if its the only way to get it right this is what I will have to do.
I have an Item table that can me link to any number of tables, and these tables may increase over time. The Item can only me linked to one other table, but the record in the other table may have many items linked to it.
Examples of the tables/entities being linked to are Person, Vehicle, Building, Office. These are all separate tables.
Example of Items are Pen, Stapler, Cushion, Tyre, A4 Paper, Plastic Bag, Poster, Decoration"
For instance a Poster may be allocated to a Person or Office or Building. In the future if they add a Conference Room table it may also be added to that.
My intital thoughts are:
Item
{
ID,
Name
}
LinkedItem
{
ItemID,
LinkedToTableName,
LinkedToID
}
The LinkedToTableName field will then allow me to identify the correct table to link to in my code.
I'm not overly happy with this solution, but I can't quite think of anything else. Please help! :)
Thanks!
It is not a good practice to store table names as column values. This is a bad hack.
There are two standard ways of doing what you are trying to do. The first is called single-table inheritance. This is easily understood by ORM tools but trades off some normalization. The idea is, that all of these entities - Person, Vehicle, whatever - are stored in the same table, often with several unused columns per entry, along with a discriminator field that identifies what type the entity is.
The discriminator field is usually an integer type, that is mapped to some enumeration in your code. It may also be a foreign key to some lookup table in your database, identifying which numbers correspond to which types (not table names, just descriptions).
The other way to do this is multiple-table inheritance, which is better for your database but not as easy to map in code. You do this by having a base table which defines some common properties of all the objects - perhaps just an ID and a name - and all of your "specific" tables (Person etc.) use the base ID as a unique foreign key (usually also the primary key).
In the first case, the exclusivity is implicit, since all entities are in one table. In the second case, the relationship is between the Item and the base entity ID, which also guarantees uniqueness.
Note that with multiple-table inheritance, you have a different problem - you can't guarantee that a base ID is used by exactly one inheritance table. It could be used by several, or not used at all. That is why multiple-table inheritance schemes usually also have a discriminator column, to identify which table is "expected." Again, this discriminator doesn't hold a table name, it holds a lookup value which the consumer may (or may not) use to determine which other table to join to.
Multiple-table inheritance is a closer match to your current schema, so I would recommend going with that unless you need to use this with Linq to SQL or a similar ORM.
See here for a good detailed tutorial: Implementing Table Inheritance in SQL Server.
Find something common to Person, Vehicle, Building, Office. For the lack of a better term I have used Entity. Then implement super-type/sub-type relationship between the Entity and its sub-types. Note that the EntityID is a PK and a FK in all sub-type tables. Now, you can link the Item table to the Entity (owner).
In this model, one item can belong to only one Entity; one Entity can have (own) many items.
your link table is ok.
the trouble you will have is that you will need to generate dynamic sql at runtime. parameterized sql does not typically allow the objects inthe FROM list to be parameters.
i fyou want to avoid this, you may be able to denormalize a little - say by creating a table to hold the id (assuming the ids are unique across the other tables) and the type_id representing which table is the source, and a generated description - e.g. the name value from the inital record.
you would trigger the creation of this denormalized list when the base info is modified, and you could use that for generalized queries - and then resort to your dynamic queries when needed at runtime.

Grouping records with or without a foreign key constraint

I have a table containing objects, something like this:
PK ObjectId
FK ObjectTypeId
Description
etc
The objects need to be grouped. I have been given a number of suggestions, all of which 'work' and some I like more than others. None of them are perfect so I'm struggling to settle on any particular model.
1/ Add a self-referential foreign key. This is clean but not ideal because (a) there is no logical parent (it's a group, not a hierarchy) and (b) it is potentially a pain for LINQ-to-SQL to traverse a self-referential hierarchy - would need to check to see if the current object is a 'parent' or a 'child' object, etc.
PK ObjectId
FK ParentObjectId
2/ Add a parent table & a foreign key. This adds constraints but the Group table doesn't contain any useful information - it exists only to provide a GroupId constraint & identity.
Table Object
PK ObjectId
FK GroupId
Table Group
PK GroupId
3/ Add a GroupId without a constraint or foreign key. No data integrity. The theory is that when a new object group is inserted, each object is given GroupId = the first assigned ObjectId. Probably the simplest & most practical solution.
e.g.
ObjectId GroupId
...
15 10
16 16
17 16
...
21 16
22 22
My question is which of these is the best in theory and/or practice, and why. Or, please tell me a better way to do this! I personally like (2) because it is normalized, but am told that a table with just one field is bad design. Thoughts and suggestions?
For option two, you can always add additional fields, for discriptions, display orders, and GroupParentID, for multiple levels of grouping. Also, you can implement securit on these grouping structures.
In our application we use that structure.
From the limited info you present it is difficult to recommend an option, because the method depends on your usage of the tables. Storing the data is one thing, but using it is a completely different issue. All three store the data is a way possible to retrieve it, however what queries will you need to construct to load it, aggregate it, and search it?
I would implement each method, populate with a small set of data and try to write a few queries to gather data as your application would. Any problems or difficulties in using the table design will become apparent then.
You should always design your tables so data retrieval is fast and easy. You shouldn't have to fight your tables to get your data out. If do you find yourself fighting with your tables to get the data out, then you designed them poorly. Your table structure should make your life easier not harder.