2

Database Schema

My question is related to ServiceASpecificField and ServiceBSpecificField. I feel that these two fields are placed inappropriately because for all records of service A for all subscribers in SubscriberServiceMap table, ServiceBSpecificField will have null value and vice versa.

If I move these two fields in Subscribers table, then I will have another problem. All those subscribers who only avail service A will have null value in Subscribers.ServiceBSpecificField.

So what should be done ideally?

IsmailS
  • 10,797
  • 21
  • 82
  • 134
  • It would be also great if someone could suggest me specific title for this question because I don't know what to call this problem in short. This will drive others to answer else the current title is so generic that many people may keep themselves from opening this post. – IsmailS Dec 24 '10 at 12:36
  • 1
    The question should be "How to Handle Optional Columns" – PerformanceDBA Dec 25 '10 at 03:34
  • @PerformanceDBA, thanks I've updated title. – IsmailS Jan 06 '11 at 12:36

4 Answers4

3

alt text

place check constraint on Service_A and _B tables like:

alter table Service_A add constraint chk_A check (ServiceID = 1);
alter table Service_B add constraint chk_B check (ServiceID = 2);

then jou can join like

select *
from SubscriberService as x
left join Service_A    as a on (a.SubscriberID = x.SubscriberID and a.ServiceID = x.ServiceID)
left join Service_B    as b on (b.SubscriberID = x.SubscriberID and b.ServiceID = x.ServiceID)
Damir Sudarevic
  • 21,891
  • 3
  • 47
  • 71
  • I had once thought of this solution. It is a very nice solution actually. But the thing is I will have to add a table every time there is an addition of a Service. – IsmailS Dec 24 '10 at 12:33
  • @Ismail -- Yes, add a table, but no need to modify any existing ones. And as long as there are relatively few services, it's OK. – Damir Sudarevic Dec 24 '10 at 12:36
  • 1
    1) agreed as well 2) I don't understand what the Check constraint does, can you please explain 3) also what is the purpose on duplicating `ServiceId` in the subtypes ? – PerformanceDBA Dec 25 '10 at 04:51
2

An easy way to do this is to ask yourself: Do the values of these columns vary according to the Subscription (SubscriberServiceMap table) or the Service?

If every subscriber of "Service A" has the same value for ServiceASpecificField, only then must you move this to the Services table.

How many such fields do you anticipate? ServiceASpecificField, ServiceBSpecificField, C, D... and so forth? If the number is sizable, you could go for an EAV model, which would involve the creation of another table.

RabidFire
  • 6,280
  • 1
  • 28
  • 24
  • Thanks. Value may differs for each Subscriber. Let me look into and see what EAV model is. – IsmailS Dec 23 '10 at 06:19
  • EAV model is a good option. Though in one of our project we are implementing a similar thing which has a `SettingKey` table having `DataType` and `DefaultValue` columns in it and then `SettingValue` table having foreign key of `SettingKeyId` column and then `SubscriberId` and `Value` columns. I think it is better than EAV model or improved version of EAV model. – IsmailS Dec 23 '10 at 06:35
2

This is a simple supertype-subtype issue which you can solve at 5NF, you do not need EAV or improved EAV or 6NF (the full and final correct EAV) for this. Since the value of ServiceAColumn is dependent on the specific subscriber's subscription to the service, then it has to be in the Associative table.

▶Normalised Data Model◀ (inline links do not work on some browsers/versions.)

Readers who are not familiar with the Relational Modelling Standard may find ▶IDEF1X Notation◀ useful.

  • This is an ordinary Relational Supertype-Subtype structure. This one is Exclusive: a Service is exclusively one Subtype.

  • The Relations and Subtypes are more explicit and more controlled in this model than in other answers. Eg. the FK Relations are specific to the Service Subtype, not the Service Supertype.

  • The Discriminator, which identifies which Subtype any Supertype row is, is the ServiceType. The ServiceType does not need to be repeated in the Subtypes, we known which subtype it is by the subtype table.

  • Unless you have millions of Services, a short code is a more appropriate PK than a meaningless number.

Other

  • You can lose the Id column in SubscriberService because it is 100% redundant and serves no purpose.

  • the PK for SubscriberService is (SubscriberId, ServiceId), unless you want duplicate rows.

  • Please change the column names: Subscriber.Id to SubscriberId; Service.Id to ServiceId. Never use Id as a column name. For PKs and FKs, alway use the full column name. The relevance of that will become clear to you when you start coding.

Sixth Normal Form or EAV

Adding columns and tables when adding new services which have new attributes, is well, necessary in a Relational database, and you retain a lot of control and integrity.

If you don't "want" to add new tables per new service then yes, go with EAV or 6NF, but make sure you have the normal controls (type safety) and Data and Referential Integrity available in Relational databases. EAV is often implemented without proper Relational controls and Integrity, which leads to many, many problems. Here is a question/answer on that subject. If you do go with that, and the Data Models in that question are not explanatory enough, let me know and I will give you a Data Model that is specific to your requirement (the DM I have provided above is pure 5NF because that is the full requirement for your original question).

Community
  • 1
  • 1
PerformanceDBA
  • 32,198
  • 10
  • 64
  • 90
-1

If the value of ServiceSpecificField depends both on service and subscriber and for all subscriber-service pairs the type of the field - is the same (as I see in your example - varchar(50) for both fields), then I would update the SubscriberSerivceMap table only:

table SubscriberSerivceMap:
Id
SubscriberId
ServiceId
SpecificField  

Example of such table:

Id             SubscriberId       Service Id       SpecifiedField
1                 1                   1             sub1_serv1
2                 1                   2             sub1_serv2
3                 2                   1             sub2_serv1
4                 2                   2             sub2_serv2
Alexandr
  • 9,213
  • 12
  • 62
  • 102
  • Can't move it to Services table as value differs for each subscriber. – IsmailS Dec 23 '10 at 06:21
  • Do you mean the value depends both on subscriber and service type? – Alexandr Dec 23 '10 at 06:27
  • Two fields are just for example. There may be a datatype difference and difference in count of columns required by each service. Some service that will be added in future may not need any field. – IsmailS Dec 24 '10 at 12:31
  • 1
    @Alexandr. -1 You have combined two columns into one, and broken Relational and Normalisation rules. How is anyone supposed to identify whether the field contains a ServiceA or ServiceB value ? – PerformanceDBA Dec 25 '10 at 03:50