SQL table design: table with multiple one-to-one relationships - sql

In SQL I have a table setup
RegisterTable
----
DocId int
status int
docType int
CarDocument Table
----
carDocId int (PK, FK -> RegisterTable)
name string
carMake varchar
EmployeeDocument
----
emplyeeDocId int (PK, FK -> RegisterTable)
name varchar
age int
This is a database about documents. Tables design have no relevance to the question.
So I have different documents Cars/Emplyees/etc... -- they all have completely different set of fields, unrelated.
I need to have metadata for these documents, which is represented in RegisterTable. This metadata is similar across documents. So it's a bit like inheritance.
Which is the DB design for this case? Currently I made three separate tables and created one-to-one relation from CarDocument/EmployeeDpcument to RegisterTable.
When I create a document, I first create it's metadata in RegisterTable, then I take the key and use it to create a document in corresponding CarDocument or EmployeeDocument table.
This works but looks cumbersome to me.
Extra info: I have 10-20 different document tables.
I use typeorm as my ORM solution.
Research:
Has similarities with Table has one to one relationship with many tables
My design works but RegisterTable is kinda fake since it holds all the docIds.
Which is the best DB design for this case?

Postgres actually does inheritance - see https://www.postgresql.org/docs/current/tutorial-inheritance.html
Aside from that, if you have metadata that is always the same across various types of documents, your approach to have a metadata table with a relation to the document tables is the right one, in principle (see below).
The metadata table itself does not need to know about the tables that reference it. Your query logic can derive the correct secondary document from the docType and the docId.
For your specific case, as you've posted it above, if a single "status" field is the only actual metadata you hold in that table, I think you would be better off to simply add that field to the document tables. Only if you have a fixed set of metadata that you don't want to replicate over many different tables does it make sense to split it into its own table.

I see nothing wrong with your design. One key point, anyway, is deciding if you'll share the IDs for all your entities/tables (as you're doing) or have separate IDs. The second choice may be the more tidy and flexible. You'll have something like this:
RegisterTable
----
docId int
status int
docType int
CarDocument
----
carDocId int (PK)
docId int (FK-> RegisterTable)
name string
carMake varchar
EmployeeDocument
----
emplyeeDocId int (PK)
docId int (FK-> RegisterTable)
name varchar
age int
Of course, you can also have just ONE big table with a lot of fields, filling each field (or not) depending on the docType, and maybe with different semantics for each different docType (no, I'm joking, don't do that).

There's a more flexible and scalable approach that can be used.
A single table would store all document metadata and then another separate table for each document type that stores specific details for that type of doc.
RegisterTable can be renamed to DocumentMetadata and contains DocId, status, docType etc.
CarDocument and EmployeeDocument tables contain columns that are specific to each type such as carMake and age.
Can bind the tables via Foreign Key from DocumentMetadata table to document-specific tables
It's not only more flexible because you can keep adding new types of docs, but also avoids creation of a meaningless table that doesn't have any real info (RegisterTable)

Related

SQL attributes depending on type

Let's say I have an entity CLIENT, which can be either PERSON or ORGANIZATION. Depending on which type it is, I have to choose attributes (address, name for organization, date_of_birth,first_name,last_name for person). I have created all three entities, but how can I make the attributes type-dependent?
Seen Database design: objects with different attributes, didn't help...
One typical choice is a 1:1 extension table:
create table client (id int primary key);
create table person (id int foreign key references client(id), ...columns...);
create table organization (id int foreign key references client(id), ...columns...);
However, my preferred choice is to include all columns in the client table. You can have a column for type that is either person or organization. Columns that are not relevant for the row's type can be null. Your queries will be much simpler that way.
Either you use 3 tables or you use 1 table and leave the not needed columns null. Which design is superior depends on the use case. Using only 1 table gives simpler queries but requires to change the table for each new subclass. Using multiple tables allows to add more types easily but gives more complicated queries. In doubt I would start with only 1 table but your mileage may vary.

Table referenced by other tables having different PKs

I would like to create a table called "NOTES". I was thinking this table would contain a "table_name" VARCHAR(100) which indicates what table put in the note, a "key" or multiple "key" columns representing the primary key values of the table that this note applies to and a "note" field VARCHAR(MAX). When other tables use this table they would supply THEIR primary key(s) and their "table_name" and get all the notes associated with the primary key(s) they supplied. The problem is that other tables might have 1, 2 or more PKs so I am looking for ideas on how I can design this...
What you're suggesting sounds a little convoluted to me. I would suggest something like this.
Notes
------
Id - PK
NoteTypeId - FK to NoteTypes.Id
NoteContent
NoteTypes
----------
Id - PK
Description - This could replace the "table_name" column you suggested
SomeOtherTable
--------------
Id - PK
...
Other Columns
...
NoteId - FK to Notes.Id
This would allow you to keep your data better normalized, but still get the relationships between data that you want. Note that this assumes a 1:1 relationship between rows in your other tables and Notes. If that relationship will be many to one, you'll need a cross table.
Have a look at this thread about database normalization
What is Normalisation (or Normalization)?
Additionally, you can check this resource to learn more about foreign keys
http://www.w3schools.com/sql/sql_foreignkey.asp
Instead of putting the other table name's and primary key's in this table, have the primary key of the NOTES table be NoteId. Create an FK in each other table that will make a note, and store the corresponding NoteId's in the other tables. Then you can simply join on NoteId from all of these other tables to the NOTES table.
As I understand your problem, you're attempting to "abstract" the auditing of multiple tables in a way that you might abstract a class in OOP.
While it's a great OOP design principle, it falls flat in databases for multiple reasons. Perhaps the largest single reason is that if you cannot envision it, neither will someone (even you) looking at it later have an easy time reassembling the data. Smaller that that though, is that while you tend to think of a table as a container and thus similar to an object, in reality they are implemented instances of this hypothetical container you are trying to put together and operate better if you treat them as such. By creating an audit table specific to a table or a subset of tables that share structural similarity and data similarity, you increase the performance of your database and you won't run in to strange trigger or select related issues later.
And you can't envision it not because you're not good at what you're doing, but rather, the structure is not conducive to database logging.
Instead, I would recommend that you create separate logging tables that manage the auditing of each table you want to audit or log. In fact, some fast google searches show many scripts already written to do much of this tasking for you: Example of one such search
You should create these individual tables and then if you want to be able to report on multiple table or even all tables at once, you can create a stored procedure (if you want to make queries based on criterion) or a view with an included SELECT statement that JOINs and/or UNIONs the tables you are interested in - in a fashion that makes sense to the report type. You'll still have to write new objects in to the view, but even with your original table design, you'd have to account for that.

How to add user customized data to database?

I am trying to design a sqlite database that will store notes. Each of these notes will have common fields like title, due date, details, priority, and completed.
In addition though, I would like to add data for more specialized notes like price for shopping list items and author/publisher data for books.
I also want to have a few general purpose fields that users can fill with whatever text data they want.
How can I design my database table in this case?
I could just have a field for each piece of data for every note, but that would waste a lot of fields and I'd like to have other options and suggestions.
There are several standard approaches you could use for solving this situation.
You could create separate tables for each kind of note, copying over the common columns in each case. this would be easy but it would make it difficult to query over all notes.
You could create one large table with many columns and some kind of type field which would let you know which type of note it is (and therefore which subset of columns to use)
CREATE TABLE NOTE ( ID int PRIMARY KEY, NOTE_TYPE int, DUEDATE datetime, ...more common fields, price NUMBER NULL, author VARCHAR(100) NULL,.. more specific fields)
you could break your tables up into a inheritance relationship something like this:
CREATE TABLE NOTE ( ID int PRIMARY KEY, NOTE_TYPE int, DUEDATE datetime, ...more common fields);
CREATE TABLE SHOPPINGLITITEM (ID int PRIMARY KEY, NOTE_ID int FORIENKEY NOTE.ID, price number ... more shopping list item fields)
Option 1 would be easy to implement but would involve lots of mostly redundant table definitions.
Option 2 would be easy to create and easy to write queries on but would be space inefficient
And option 3 would be more space efficient and less redundant but would possibly have slower queries because of all the foreign keys.
This is the typical set of trade-offs for modeling these kinds of relationships in SQL, any of these solutions could be appropriate for use case depending non your performance requirements.
You could create something like a custom_field table. It gets pretty messy once you start to normalize.
So you have your note table with it's common fields.
Now add:
dynamic_note_field
id label
1 publisher
2 color
3 size
dynamic_note_field_data
id dynamic_note_field_id value
1 1 Penguin
2 1 Marvel
3 2 Red
Finally, you can relate instances of your data with the fields they use through
note_dynamic_note_field_data
note_id dynamic_note_field_data_id
1 1
1 3
2 2
So now we've said: note_id 1 has two additional fields. The first one has a value "Penguin" and represents a publisher. The second one has a value of "Red" and represents a color.
So what's the point of normalizing it this far?
You're not wasting space adding fields to every item (you relate a note with it's additional dynamic field via the m2m table).
You're not storing redundant labels (you may continue to store redundant data however as the same publisher is likely to appear many times... this aspect is extremely subjective. If you want rich data about your publishers you typically want to take the step of turning them into their own entity rather than an ad-hoc string. Be careful when making this leap because it adds an extra level of hairiness to the db. Evaluate the use case accordingly.
The dynamic_note_field acts as your data definition. If you're interested in answering a question such as "what are the additional fields I've created" this lets you do it easily without searching all of your dynamic_note_field_data. Eventually, you might add extra info to this table such as a type field. I like to create this separation off the bat, but that might be a violation of the YAGNI principle in your case.
Disadvantages:
It's not too bad to search for all notes that have a publisher, where that publisher is "Penguin".
What's tricky is something like "Find any note with a value of 'Penguin' in any field". You don't know up front which field's your searching. At this point you're better off with a separate index that's generated alongside your normalized db data which acts as the point of truth. Again, the nice thing about normalization is that you maintain the data in a very lossless, non-destructive state.
For data you want to store but does not have to be searchable, another option is to serialize it to/from JSON and store it in a TEXT column. This gives you arbitrary structure, but you cannot readily query against those values.
Yet another option is to dump SQLite and go with an object database. I seem to recall there are one or two working for Android. I have not tried any of these, however.
Just create a small table which contains the common fields of all your notes.
Then a table for each class of special notes you have, that that contains all the extra fiels plus a reference on your first table.
For each note you will enter, you create a row in your main table (that contains the common fields) and a row in your extra table that contains the extra fields, and a reference to the row in your main table.
Then you will just have to make a join in you request.
With this solution :
1)you have a safe design (can't access fields that are not part of your note)
2)your db will be optimized

Dictionary table relationships (MS SQL 2005)

I have table named 'Dictionary' with columns as follow:
ID bigint
TYPE varchar (200)
ITEM varchar (200)
Table is used by various tables as simple dictionary / lookup.
Eg it stores countries, titles, business type lists.
TYPE column keeps info about type of dictionary , ITEM is dictionary string value.
All works well but I have problem to set up relationship between dictionary and foreigin tables.
When I'm using 'Foreign Key Relationship' I can not make it depended of 'TYPE" column.
(Please note same item with same type - eg 'countries' can be linked to several tables, when item with another type can be linked to different)
Currently I'm using USPs to manage that but I'd like to switch to standard relationship mechanism.
Any advice how to get that?
It looks to me that you could consider an alternative design
Dictionary table
ID (pk)
DICTIONARY_TYPE_ID (fk to dictionaryType)
ITEM
DictionaryType table
ID (pk)
DESCRIPTION
and then make links to the ID of DictionaryType table in places where you currently want to reference Type field from your original design
From the context of the question, I'm guessing you'll need to do one of two things:
Make your Type column the primary key
or have the foreign keys depend on the ID field here.
Foreign keys need to refer to a primary key, and it looks like your Type column isn't a PK.
what you have here is an EAV db design which is bad for number of reasons one being your problem. there is no solution for this in the real sense. you might try using sql_variant as a column type for the item and try to to a PK-FK relationship on that.
there's another way you could try to do this with the xml datatype and schemas like i describe here. however you'll have to test this to see if it applies to your problem.

Enumerations in the database and O/RM

Suppose I want entries in the table Regions to have a type, e.g. a city, a country etc. What's the accepted way of storing this type, assuming I'll be using O/RM (NHibernate in my case) ? I see two options:
Have an enum in the C# bussines layer with the types and store the type as a tinyint in the table.
Have a lookup table RegionTypes with the type identifiers (strings or ints) and reference them in the Regions table.
The second approach seems more reasonable from the database point of view, since I have foreign key constraints, plus I can have additional data about the region types, e.g. a city is a child type for country (and since I'm using SQL Server 2008 spatial features, I actually need this information for spatial manipulations). However, looking from the C# point of view, I'll basically have to have an entity RegionType and load it from the database every time i want to assign it to a region (as I understand NHibernate wouldn't allow me to make the type an enum if I store it in a lookup table). This is a little tedious for such a simple task, knowing that region types are basically fixed and unlikely to change.
What about other types, like DayOfWeek which are unlikely to ever change or have additional properties, should they have their lookup tables and entities ?
General rule is to use Enums if you are sure that set of values will never be changed by user. Otherwise it's better to use lookup table.
One reason to use lookup tables is the common use case of displaying the possible values in a menu or something. It's easy to query a lookup table, but less easy if the enum is hard-coded in a database data type or constraint, or in a C# enum.
I usually go with the latter option, though, I'll create a generic sort of set up where items of multiple types can be stored in the same table so that I don't end up with 15 types tables. The basics are something like this
Types
TypeID int,
Name varchar(20),
Description varchar(100)
Type_Items
ItemID int,
TypeID int -> Types.TypeID,
Name varchar(20),
Description varchar(100),
Value varchar(100)