If you have the following class:
Public Class Male
Inherits Person
Private Age As integer
Private TelephoneNumber As String
End Class
and the following table
CREATE TABLE Person (ID int identity not null, Age int, TelephoneNumber varhchar(30), sex varhchar(6), primary key (ID))
In order to populate the Male class you would have to run an SQL statement, saying: WHERE Sex='MALE'. Is this a poor design choice where one database table has two classes? i.e. there is a one to many relationship.
This is Table per Class Hierarchy, and is perfectly acceptable. This design pattern uses a single table to store multiple subclasses and uses a discriminator (in your case Sex) to distinguish between them.
Related
Example:
I have a base table called Pet with a BirthDate and Name columns.
I have a two more tables that derive from that table, one called PetDog table with column NumberOfTeeth and another called PetBird table with column BeakColor.
How to implement this using Kotlin Exposed? https://github.com/JetBrains/Exposed
Or is there any documentation on this available?
What sort of database and schema do you have in mind? How does it support table inheritance? As Михаил Нафталь already mentioned in the comment, a common approach with a relational database would be to either use one table with all columns or two tables (pet and dog, with some way to link the records in both tables to each other).
A simple example with two tables:
create table pet (id int auto_increment primary key, birthdate varchar(10) not null, "name" varchar(50) not null)
create table dog (id int auto_increment primary key, pet_id int not null, number_of_teeth int not null, constraint fk_dog_pet_id_id foreign key (pet_id) references pet(id) on delete restrict on update restrict)
Your Exposed table definition code could then look something like this:
object Pet : IntIdTable() {
val birthdate = varchar("birthdate", 10)
val name = varchar("name", 50)
}
object Dog : IntIdTable() {
val petId = reference("pet_id", Pet).nullable()
val numberOfTeeth = integer("number_of_teeth")
}
I would like to know if there's a better way to design this kind of relationships within Postgre:
Basically, I've got some entities that are either an EntityA, an EntityB or an EntityC. I will have plenty of other relationships between entities and other stuff (like Comment in this case) so I've got this generic Entity that defines which type of Entity it's linked to.
As an example, if we have an EntityA linked to a comment, the Entity entry will look like:
type: EntityA
entity_a_id: x
entity_b_id: null
entity_c_id: null
Is there a better way to design this?
This seems a good fit for the Table Inheritance feature
CREATE TABLE entity (
-- columns that are shared among all entities
);
CREATE TABLE entity_a (
-- columns that are unique for this entity type
) INHERITS (entity);
CREATE TABLE entity_b (
-- columns that are unique for this entity type
) INHERITS (entity);
This way, entity types do not include columns of other types
How different are the entities?
Why not just
CREATE TABLE Entity
(
EntityId int,
EntityType enum(A, B, C),
FieldValue varchar(255)
)
or if the field values are significantly different and don't make sense in a single column,
CREATE TABLE Entity
(
EntityId int,
EntityType enum(A, B, C),
FieldValueX varchar(255),
FieldValueY varchar(255),
FieldValueZ varchar(255)
)
In an existing SQL Server database, someone has defined the following:
Table Customer has a CustomerID column which is also identity. Then they have defined a relationship where Customer.CustomerID is primary key and Customer.CustomerID is also foreign key. I.e. the relationship points back to the same table and same column.
What is the purpose of this? Seems entirely pointless to me, so I plan to remove this relationship from the DB.
The relation is called a recursive association or reflexive relationship, you will need this type of relationship when you need to present a relationship between two or more elements of the same type.
For example: for presenting a relationship between employees, you could create two tables Employee and Manager. But because the manager is also an employee, you won't need two tables. So we create a recursive association that point for the same entity.
More about recursive association
UPDATE
Setting a column as PK and FK at the same time could also represent the concept of inheritance.
For example:
class Person {
int ID;
string name;
}
class Customer extends Person {
String workPlace;
}
That would result the tables Person and Customer as listed below:
Person
------------
int id (PK)
string name
Employee
--------------
int id (PK, FK)
string workPlace
I have implemented the following ways of storing relational topology:
1.A general junction relation table:
Table: Relation
Columns: id parent_type parent_id parent_prop child_type child_id child_prop
On which joins are not generally capable of being executed against by most sql engines.
2.Relation specific junction tables
Table: Class2Student
Columns: id parent_id parent_prop child_id child_prop
On which joins are capable of being executed against.
3.Storing lists/string maps of related objects in a text field on both bidirectional objects.
Class: Class
Class properties: id name students
Table columns: id name students_keys
Rows: 1 "history" [{type:Basic_student,id:1},{type:Advanced_student,id:3}]
To enable joins by the sql engines, it would be possible to write a custom module which would be made even easier if the contents of students_keys was simply [1,3], ie that a relation was to the explicit Student type.
The questions are the following in the context of:
I fail to see what the point of a junction table is. For example, I fail to see that any problems the following arguments for a junction table claim to relieve, actually exist:
Inability to logically correctly save a bidirectional relations (eg
there is no data orphaning in bidirectional relations or any
relations with a keys field, because one recursively saves and one can enforce
other operations (delete,update) quite easily)
Inability to join effectively
I am not soliciting opinions on your personal opinions on best practices or any cult-like statements on normalization.
The explicit question(s) are the following:
What are the instances where one would want to query a junction table that is not provided by querying a owning object's keys field?
What are logical implementation problems in the context of computation provided by the sql engine where the junction table is preferable?
The only implementation difference with regards to a junction table vs a keys fields is the following:
When searching for a query of the following nature you would need to match against the keys field with either a custom indexing implementation or some other reasonable implementation:
class_dao.search({students:advanced_student_3,name:"history"});
search for Classes that have a particular student and name "history"
As opposed to searching the indexed columns of the junction table and then selecting the approriate Classes.
I have been unable to identify answers why a junction table is logically preferable for quite literally any reason. I am not claiming this is the case or do I have a religious preference one way or another as evidenced by the fact that I implemented multiple ways of achieving this. My problem is I do not know what they are.
The way I see it, you have have several entities
CREATE TABLE StudentType
(
Id Int PRIMARY KEY,
Name NVarChar(50)
);
INSERT StudentType VALUES
(
(1, 'Basic'),
(2, 'Advanced'),
(3, 'SomeOtherCategory')
);
CREATE TABLE Student
(
Id Int PRIMARY KEY,
Name NVarChar(200),
OtherAttributeCommonToAllStudents Int,
Type Int,
CONSTRAINT FK_Student_StudentType
FOREIGN KEY (Type) REFERENCES StudentType(Id)
)
CREATE TABLE StudentAdvanced
(
Id Int PRIMARY KEY,
AdvancedOnlyAttribute Int,
CONSTRIANT FK_StudentAdvanced_Student
FOREIGN KEY (Id) REFERENCES Student(Id)
)
CREATE TABLE StudentSomeOtherCategory
(
Id Int PRIMARY KEY,
SomeOtherCategoryOnlyAttribute Int,
CONSTRIANT FK_StudentSomeOtherCategory_Student
FOREIGN KEY (Id) REFERENCES Student(Id)
)
Any attributes that are common to all students have columns on the Student table.
Types of student that have extra attributes are added to the StudentType table.
Each extra student type gets a Student<TypeName> table to store its specific attributes. These tables have an optional one-to-one relationship with Student.
I think that your "straw-man" junction table is a partial implementation of an EAV anti-pattern, the only time this is sensible, is when you can't know what attributes you need to model, i.e. your data will be entirely unstructured. When this is a real requirment, relational databases start to look less desirable. On those occasions consider a NOSQL/Document database alternative.
A junction table would be useful in the following scenario.
Say we add a Class entity to the model.
CREATE TABLE Class
(
Id Int PRIMARY KEY,
...
)
Its concievable that we would like to store the many-to-many realtionship between students and classes.
CREATE TABLE Registration
(
Id Int PRIMARY KEY,
StudentId Int,
ClassId Int,
CONSTRAINT FK_Registration_Student
FOREIGN KEY (StudentId) REFERENCES Student(Id),
CONSTRAINT FK_Registration_Class
FOREIGN KEY (ClassId) REFERENCES Class(Id)
)
This entity would be the right place to store attributes that relate specifically to a student's registration to a class, perhaps a completion flag for instance. Other data would naturally relate to this junction, pehaps a class specific attendance record or a grade history.
If you don't relate Class and Student in this way, how would you select both, all the students in a class, and all the classes a student reads. Performance wise, this is easily optimised by indices on key columns.
When a many-to-many realtionships exists without any attributes I agree that logically, the junction table needn't exist. However, in a relational database, junction tables are still a useful physical implmentaion, perhaps like this,
CREATE TABLE StudentClass
(
StudentId Int,
ClassId Int,
CONSTRAINT PK_StudentClass PRIMARY KEY (ClassId, StudentId),
CONSTRAINT FK_Registration_Student
FOREIGN KEY (StudentId) REFERENCES Student(Id),
CONSTRAINT FK_Registration_Class
FOREIGN KEY (ClassId) REFERENCES Class(Id)
)
this allows simple queries like
// students in a class?
SELECT StudentId
FROM StudentClass
WHERE ClassId = #classId
// classes read by a student?
SELECT ClassId
FROM StudentClass
WHERE StudentId = #studentId
additionaly, this enables a simple way to manage the relationship, partially or completely from either aspect, that will be familar to relational database developers and sargeable by query optimisers.
Here's an SQL Server / ADO.Net Entity Framework question: I'm looking for the "best" way to do this.
I have a hierarchical structure of objects similar to the following:
Company -> Division -> Department -> Group -> Specialty
The primary key of each (other than Company) consists of a foreign key pointing to the PK of each of its ancestors. So, Specialty looks like this:
[PK/FK] CompanyID (string)
[PK/FK] DivisionID (int)
[PK/FK] DepartmentID (int)
[PK/FK] GroupID (int)
[PK] SpecialtyID (int)
Name (string)
Description (string)
This basic structure has to remain in place for reasons I won't go into - so using a GUID as the PK really isn't in the cards -- we have to interface with other apps that rely on the "Bergdorf.6.3.4.1" ID construct that this structure reflects.
What I need to do now, though, is add the ability to add a Specialty which applies to an entire Department, rather than to a group. So, in an ideal world, we'd have this:
[PK/FK] CompanyID (string)
[PK/FK] DivisionID (int)
[PK/FK] DepartmentID (int)
[PK/FK] GroupID (int/NULL)
[PK] SpecialtyID (int)
Name (string)
Description (string)
...such that if the Specialty's GroupID is null, that means it applies to the whole department.
But, of course, you can't have a nullable field as part of a PK. So that's a no-go.
It also won't work to just pull GroupID out of the PK, because then SpecialtyID is going to have to be unique across an entire Department, and we already have established IDs that make that impossible.
Can't make a "special" GroupID (e.g. "-1") that means "No Group", because the FK constraints would require us to create a Group with an ID of -1 for every single Department.
...So... what's the right thing to do here? Do I have to make a GUID for Specialty, and pull all those FKs out of the PK? Would really like to avoid that if possible.
Any ideas would be much appreciated!
I recommend you have two (subtype) base tables with no nullable columns: one for Department Specialties and another for Group Specialties. You'll probably want a third (supertype) table for all specialities so that you can have SpecialtyID values that are unique to all Specialties regardless of subtype.
Then you coould have a VIEW that UNIONs the subtypes together and here you can introduce a default value (e.g. -1) for the 'missing' GroupIDs for Department Specialities. You could go further and only expose the VIEW, don't expose the base tables and use INSTEAD OF triggers on the VIEW to hande updates to the base table.
You would anyhow need a mechanism to ensure that for every Specialty (supertype) created exactly one Department Specialty or Group Specialty is also created e.g. you could revoke all write permissions on all realted base tables and VIEWs and force users to create Specialties uses CRUD procedures you've coded to ensure the super/subtype requirements are always satisfied.
You could create a "null-buster" computed column, based on the nullable GroupID column, and make it part of the PK instead of GroupID:
create table Specialities (
CompanyID varchar(10) not null,
DivisionID int not null,
DepartmentID int not null,
GroupID int null,
SpecialityID int not null,
Name varchar(10) not null,
Description varchar(max) not null,
_NNGroupID as ISNULL(GroupID,-1),
constraint PK_Specialities PRIMARY KEY (CompanyID,DivisionID,DepartmentID,_NNGroupID,SpecialityID)
)
I'm not sure whether I like this idea or not, but it may be an option for you. This assumes that no real GroupID of -1 will ever exist - you may have to pick a different magic value for your purposes. So long as the value on the right-hand side of the ISNULL is not part of the domain of real GroupIDs, this should work.
You continue to have the foreign key defined against GroupID rather than _NNGroupID so that the nullable-ness of the foreign key constraint works as you expect.
You could create an xref table linking Specialty with Department: xSpecialtyDepartment(SpecialtyID int, DepartmentID int)