1

I'm working on a database design, and I face a situation where notifications will be sent according to logs in three tables, each log contains different data. NOTIFICATIONS table should then refer these three tables, and I thought of three possible designs, each seems to have flaws in it:

  1. Each log table will have a unique incremented id, and NOTIFICATIONS table will have three different columns as FK's. The main flaw in this design is that I can't create real FK's since two of the three fields will be NULL for each row, and the query will have to "figure out" what kind of data is actually logged in this row.
  2. The log tables will have one unique incremented id for all of them. Then I can make three OUTER JOINS with these tables when I query NOTIFCATIONS, and each row will have exactly one match. This seems at first like a better design, but I will have gaps in each log table and the flaws in option 1 still exist.
  3. Option 1/2 + creating three notifications tables instead of one. This option will require the app to query notifications using UNION ALL.

Which option makes a better practice? Is there another way I didn't think of? Any advice will be appreciated.

Neria Nachum
  • 1,519
  • 1
  • 20
  • 37

3 Answers3

0

Use one table holding notification ids. Each of the three original tables hold subtypes of notification ids with FKs on their own ids to that table. Search re subtyping/subtables in databases. This is a standard design pattern/idiom.

(There are entities. We group them conceptually. We call the groups kinds or types. We say of a particular entity that it is a whatever kind or type of entity, or even that it "is a" whatever. We can have groups that contain all the entities of another group. Since the larger is a superset of the smaller we say that the larger type is a supertype of the smaller type, and the smaller is a subtype of the larger.)

There are idioms you can use to help constrain your tables declaratively. The main one is to have a subtype tag in the supertype table, and even also in the subtype tables (where each table has only one tag value).

philipxy
  • 14,867
  • 6
  • 39
  • 83
0

I have one solution that sacrifices the referential integrity to help you achieve what you want.

You can keep a GUID data type as the primary key in all three log tables. In the Notification table you just need to add one foreign key column which won't point to any particular table. So only you know that it is a foreign key, SQL Server doesn't and it doesn't enforce referential integrity. In this column you store the GUID of notification. The notification can be in any of the three logs but since the primary key of all three logs is GUID, you can store the key in your Notification table.

Also you add another column in the Notification table to tell which of the three logs this GUID belongs to. Now you can uniquely know which row in the required log table you have to go to in order to find this notification info.


The problem is that you have three separate log tables. Instead you should have had only log table which would have an extra column specifying what kind of logging is it. That way you'd have only one table - referential integrity would have stayed and design would have been simple.

displayName
  • 13,888
  • 8
  • 60
  • 75
  • Thanks for the advice regarding adding a type column in NOTIFICATIONS. The main reason I prefer three log tables is that I have different type of data logged in it (for example, one logs status changes + reason and the other logs simple text messages). Thus, some columns are relevant for particular logging, and considering the option of adding more types of logging, that seems a bit frightening. – Neria Nachum Dec 05 '15 at 20:50
  • @NeriaNachum: I feel that you should redesign the log table and maybe rename the columns to a more generic name. For ex: a column named `Action` would hold status change+reason for one logging and txt message for another logging. Maybe name the column `ReasonOrMessage` if that is more suitable, why not? – displayName Dec 05 '15 at 21:16
0

I eventually faced two main options:

  1. Following the last suggestion in this answer.
  2. Choosing a less normalized structure for the database, AKA fake/no FK's. To be precise, in my case it would be my second option above with fake FK's.

I chose option #2 as a DBA whom I consulted enlightened me on the idea that database normalization should be done according to possible structure breakage. In my case, although notifications are created based on logs, these FK's are not necessary for querying the notifications nor for querying the log and the app do not have to ensure this relationship for a proper functioning. Thus, following option #1 may be "over-normalization".

Thanks all for your answers and comments.

Community
  • 1
  • 1
Neria Nachum
  • 1,519
  • 1
  • 20
  • 37