Unique constraint across different classes/tables (TABLE PER SUBCLASS) - sql

I have a class A and a class B that inherits from A. Class A has a certain attribute X. Class B adds another attribute Y. An instance of B is uniquely identified by its pair of attributes {X,Y}. So, {X,Y} is a candidate key for class B. Obviously this key doesn't exist at the class A level since attribute Y isn't there. I use a surrogate key for class A.
Now, I use Hibernate for the object-relational mapping. If I use the TABLE PER SUBCLASS inheritance strategy, I don't see a possibility for defining a UNIQUE constraint on multiple attributes that belong to different classes (and then in the DB, to different tables).
My question is how can I define a unique constraint for this candidate key using Hibernate and more generally in SQL? If it's not possible, what do you recommend?
Thanks

Here are two solutions:
Create a new table with one column which is its PK. This table should hold all the values which you want to make unique. Create foreign keys to this table which will ensure that the domain on the columns comes from the unique table.
Create triggers which raise an error if the condition is violated.

Related

Questionable SQL Relationship

I am going through a pluralsight course that is currently going through building an MVC application using an entity framework code-first approach. I was confused about the Database schema used for the project.
As you can see, the relationship between Securities and it's relating tables seems to be one-to-one, but the confusion comes when I realize there is no foreign key to relate the two sub-tables and they they appear to share the same primary key column.
The video before made the Securities model class abstract in order for the "Stock" and "MutualFund" model classes to inherit from it and contain all relating data. To me however, it seems that same thing could be done using a couple of foreign keys.
I guess my question is does this method of linking tables serve any useful purpose in SQL or EF? It seems to me in order to create a new record for one table, all tables would need a new record which is where I really get confused.
In ORM and EF terminology, this setup is referred to as the "Table per Type" inheritance paradigm, where there is a table per subclass, a base class table, and the primary key is shared between the subclasses and the base class.
e.g. In this case, Securities_Stock and Securities_MutualFund are two subclasses of the Securities base class / table (possibly abstract).
The relationship will be 0..1 (subclass) to 1 (base class) - i.e. only one of the records in Securities_MutualFund or Securities_Stock will exist for each base table Securities row.
There's also often a discriminator column on the base table to indicate which subclass table to join to, but that doesn't seem to be the case here.
It is also common to enforce referential integrity between the subclasses to the base table with a foreign key.
To answer your question, the reason why there's no FK between the two subclass instance tables is because each instance (with a unique Id) will only ever be in ONE of the sub class tables - it is NOT possible for the same Security to be both a mutual fund and a share.
You are right, in order for a new concrete Security record to be added, a row is needed in both the base Securities Table (must be inserted first, as their are FK's from the subclass tables to the base table), and then a row is inserted into one of the subclass tables, with the rest of the 'specific' data.
If a Foreign Key was added between Stock and Mutual Fund, it would be impossible to insert new rows into the tables.
The full pattern often looks like this:
CREATE TABLE BaseTable
(
Id INT PRIMARY KEY, -- Can also be Identity
... Common columns here
Discriminator, -- Type usually has a small range, so `INT` or `CHAR` are common
);
CREATE TABLE SubClassTable
(
Id INT PRIMARY KEY, -- Not identity, must be manually inserted
-- Specialized SubClass columns here
FOREIGN KEY (Id) REFERENCES BaseTable(Id)
);

Writing an SQL relation?

A collection of puzzles is classified as 'easy', 'moderate' or 'challenging'. Each puzzle belongs to exactly one class. Here is a simplified version of the puzzle relation:
Student{puzzle_number:integer, description:text, class:text}
Write an SQL definition for this relation. Your definition should include a primary key constraint on puzzle_number and a check constraint at table level to enforce the requirement that the value of 'class' is one of 'easy', 'moderate' or 'challenging'
I am unsure what is meant by an SQL definition? Does it mean a create table statements?
Based on the context, I would assume it means to write a "CREATE TABLE" statement that includes table name, column names, their corresponding data types, as well as the constraint mentioned, that could be used to store data that would be used to hydrate the class. So for example, the table definition must be able to store a row that has columns such as (202, "Rubik's Cube", "moderate") that represent the puzzle_number, description, and class respectively.
You can enforce the constraint mentioned by using a foreign key to a second table that stores the puzzle classifications, or you can use a check constraint when defining the table to make sure it holds one of the 3 values allowed without having to use a second table.
Simple Create Table reference:
http://www.w3schools.com/sql/sql_check.asp
Simple Check constraint reference:
http://www.w3schools.com/sql/sql_check.asp

How to reverse the dependencies of a foreign key constraint?

Suppose I have two concepts, Teacher and Class. They map nicely to two database tables, Teachers and Classes. To express the statement 'every Class has a Teacher' I add a foreign key to the Classes table pointing to the Teachers table. Now if I try and delete a Teachers row that is used in a Class, I get a nice error saying 'Can't do that' which is what I want.
So far so good. But what if I wanted to extend this behaviour onto Pupils? I.e. whenever I try to delete a Pupil that is part of a class I want the database engine to roar at me and say 'Can't do that'.
I could simulate what I want by creating 30 foreign keys in Classes: Pupil_1_ID, Pupil_2_ID, ... Pupil_30_ID. But what I'm really after is doing this for an arbitrary number of Pupils.
How can I achieve this?
Create a surrogate key table, PupilClass that has an FK to Class and another FK to Pupils. This way to you can't delete a pupil who's in a class, and neither can you delete a class that has pupils.
A surrogate table is a common design pattern when you need to model a many-to-many relationships: a class can have many pupils, a pupil can attend many classes.

obtaining foreign key from DEPENDENT possibility in create table SQL

Lets say you have two entity named Parent and Child.
Child entity is DEPENDENT of Parent entity.
A weak key of child entity is the NAMEOFCHILD.
Is it possible for the Parent entity to have NAMEOFCHILD as a foreign key?
This idea has not been talked about in class. I was wondering is this possible in SQL?
If so, should i just add
FOREIGN KEY (NAMEOFCHILD) source CHILD
in my table?
In the database schema, yes (if Child.NAMEOFCHILD has a unique index). In entity framework, no. EF doesn't support associations to unique indexes (yet). But this is just on the technical level. Whether it's meaningful is another question.
Also, beware of painting yourself in a corner. When both foreign keys are not nullable you'd never be able to insert data, because you can't insert two records at a time and sequential inserts always cause foreign key violations. You would be able to design the database schema but never get any data in.

Can a foreign key have a constant instead of a field name? Relate FK to STI subclass

Setup
So here's a scenario which I'm finding is rather common once you decide to play with STI (Single Table Inheritance).
You have some base type with various subtypes.
Person < (Teacher,Student,Staff,etc)
User < (Member,Admin)
Member < (Buyer,Seller)
Vehicle < (Car,Boat,Plane)
etc.
There are two major approaches to modelling that in the database:
Single Table Inheritance
One big table with a type field and a bunch of nullable fields
Class Table Inheritance
One table per type with shared PK (FK'd from the children to the parent)
While there are several issues with STI, I do like how it manages to cut down on the number of joins you have to make, as well as some of the support in frameworks like Rails, but I am running into an issue on how to relate subclass-specific tables.
For example:
Certifications should only reference Teacher-Persons
Profiles should only reference Member-Users
WingInformation should be not be related to a car or boat (unless you are Batman maybe)
Advertisements are owned by Seller-Members not Buyer-Members
With CTI, these relationships are trivial - just slap a Foreign Key on the related table and you're done:
ALTER TABLE advertisements
ADD FOREIGN KEY (seller_id) REFERENCES sellers (id)
But with STI, the similar thing wouldn't capture the subtype restriction.
ALTER TABLE advertisements
ADD FOREIGN KEY (seller_id) REFERENCES members (id)
What I would like to see is something like:
* Does not work in most (all?) databases *
ALTER TABLE advertisements
ADD FOREIGN KEY (seller_id, 'seller') REFERENCES members (id, type)
All I have been able to find is a dirty hack requiring adding a computed column to the related table:
ALTER TABLE advertisements
ADD seller_type VARCHAR(20) NOT NULL DEFAULT 'seller'
ALTER TABLE advertisements
FOREIGN KEY (seller_id, seller-type) REFERENCES members (id, type)
This strikes me as odd (not to mention inelegant).
The real questions
Is there a RDBMS out there which will allow me to do this?
Is there a reason why this isn't even possible?
Is this just one more reason why NOT to use STI except in the most trivial of cases?
There's no standard way to declare a constant in the foreign key declaration. You have to name columns.
But you could force the column to have a fixed value, using one of the following methods:
Computed column
CHECK constraint
Trigger before INSERT/UPDATE to overwrite any user-supplied value with the default value.