views:

91

answers:

4

Hi, I would like your advice regarding Data Base design, I am new to it :-). I have 4 different data elements (tables A,B,C,D) example: A - Contents B - Categories C - Authors and D - Images

Every record in tables A,B,C could have associated 1 or more different Images in Table D, BUT for every image in D must be uniquely associated only a record in A,B,C. This means that images cannot be shared (between others tables).

My idea was to create different Image tables for every data elements, using ONE to MANY association type. Example: Content --> Image-Contents and Categories --> Image-Categories

Questions? My database design is a good one?

Since Tables "Image-Contents" and "Image-Categories", could have similar property like "File-Url" or "Image-Title", I was concerning if could be exist a most suitable database design solution.

Thanks for your time

A: 

I think you would want a table that maps each of ABC to an image. For example:

Content   -> ContentImages -> Images
---------    -------------    ------
ContentId    ImageId          ImageId
             ContentId

Categories -> CategoryImages   -> Images
----------    ----------------    ------
CategoryId    ImageId             ImageId
              CategoryId

Authors    -> AuthorImages     -> Images
----------    ----------------    ------
AuthorId      ImageId             ImageId
              AuthorId

It may seem a little cumbersome but i think this is the normal form.

Abe Miessler
+1  A: 

Perhaps the most common way to implement this design is with the "one table per owner type" scheme you mentioned (Tables for Images, "Owner A", "Owner A Images", and repeat for owners B, C, etc). Another common way to implement this is with one "central" table for Images, with the single owner's Id stored within that table. Your criteria are particularly limiting, in that an image may be associated with one and only one owner, but there are multiple types of owner. Implementing such constraints inside the database is tricky, but implementing them outside of the database is much more difficult and problematic for all the usual reasons (application doing the databases work, and what happens when someone modifies the database outside of the dedicated application?)

The following is an example of how these structures and constraints might be implemented within the database. It may appear fussy, detailed, and overly-complex, but it will do the job, and once properly implemented you would never have to worry whether or not your data was consistant and valid.

First off, all images are stored in the following table. It must be known what "type" of owner an image may be assigned to; set that in ImageType, and (as per the constraints in the later tables) the image can not be assigned to any other kind of owner. Ever. (You could also put a CHECK constraint on ImageType to ensure that only valid image types could be loaded in the table.)

CREATE TABLE Image
 (
   ImageId    int      not null
  ,ImageType  char(1)  not null
  ,constraint PK_Image
    primary key clustered (ImageId, ImageType)
 )

Next, build some owner tables. You could have any number of these, I'm just making two for sake of the example.

CREATE TABLE A
 (
   AId  int  not null
    constraint PK_A
     primary key clustered   
 )

CREATE TABLE B
 (
   BId  int  not null
    constraint PK_B
     primary key clustered   
 )

Build the association tables, noting the comments next to the constraint definitions. (This is the overly-fussy part...)

CREATE TABLE Image_A
 (
   ImageId    int  not null
    constraint PK_Image_A
     primary key clustered  --  An image can only be assigned to one owner
  ,AId        int  not null
  ,ImageType  char(1)  not null
    constraint DF_Image_A
     default 'A'
    constraint CK_Image_A__ImageType
     check (ImageType in ('A'))  --  Always have this set to the type of the owner for this table
  ,constraint FK_Image_A__A
    foreign key (AId) references A (AId)  --  Owner must exist
  ,constraint FK_Image_A__Image
    foreign key (ImageId, ImageType) references Image (ImageId, ImageType)  --  Image must exist *for this type of owner*
 )

--  Same comments for this table
CREATE TABLE Image_B
 (
   ImageId    int  not null
    constraint PK_Image_B
     primary key clustered
  ,BId        int  not null
  ,ImageType  char(1)  not null
    constraint DF_Image_B
     default 'B'
    constraint CK_Image_B__ImageType
     check (ImageType in ('B'))
  ,constraint FK_Image_B__B
    foreign key (BId) references B (BId)
  ,constraint FK_Image_B__Image
    foreign key (ImageId, ImageType) references Image (ImageId, ImageType)
 )

Load some sample data

INSERT Image values (1, 'A')

INSERT Image values (2, 'A')
INSERT Image values (3, 'B')
INSERT Image values (4, 'B')

INSERT A values (101)
INSERT A values (102)

INSERT B values (201)
INSERT B values (102)

View the current contents of the tables:

SELECT * from A
SELECT * from B
SELECT * from Image
SELECT * from Image_A
SELECT * from Image_B

And do some tests:

--  Proper fit
INSERT Image_A (ImageId, AId) values (1, 101)
--  Run it again, can only assign once

--  Cannot assign the same image to a second owner of the proper type
INSERT Image_A (ImageId, AId) values (1, 102)

--  Can't assign image to an invalid owner type
INSERT Image_B (ImageId, BId) values (1, 201)

--  Owner can be assigned multiple images
INSERT Image_A (ImageId, AId) values (2, 101)

(This drops the testing tables)

drop table Image
drop table A
drop table B

drop table Image_A
drop table Image_B

(Techincally, this is a good example of a variant on the exclusive type/subtype data modelling "problem".)

Philip Kelley
this is a seriously long answer... hard to even verify - but looks correct :)
Randy
I'd heard about this strategy a few months back, and this seemed a good time to try it out. For ease of use you could drop a partitioned view on top of the Image_X tables, but I left that out as it was already messy enough.
Philip Kelley
Thanks guys for your design, I need try it and I come back to you asap.
GIbboK
Thanks Philip, I tested your script and is working just fine.My only concern now is about PERFORMANCE, do you think quesry could be faster if I keep my first design? My idea was to create different Image tables for every data elements, using ONE to MANY association type. Example: Content --> Image-Contents and Categories --> Image-Categories
GIbboK
Performance totally depends on what kinds of queries you are performing. With proper indexes, retrieving one row should be blazingling fast; with poor indexes, you'll end up running table scans on everything. I put what I thought were "default/obvious" indexes on the tables; extra indexes on the "Image_X.XId" columns should help, if those tables get big enough. Best advice here is to stuff your dev tables with megabytes of data, run your routine queries against them, and work from there.
Philip Kelley
A: 
create table A (IDA int not null, primary key(IDA));
create table B (IDB int not null, primary key(IDB));
create table C (IDC int not null, primary key(IDC));

create table Image(IDI int, A int null, B int null, C int null, Contents image,
foreign key (A) references A(IDA),
foreign key (B) references B(IDB),
foreign key (C) references C(IDC),
check (
(A is not null and B is null and C is null) or
(A is null and B is not null and C is null) or
(A is null and B is null and C is not null)
));
pascal
A: 

Yes, you're looking in the right direction.

Keep your current setup of the four tables and then create 3 more that hold only metadata that tells you the linking between, for example, the content table and the image tables.

For example, the images-content table will have columns: id, content-id, image-id

And so on.

zaf