Question

I have the following table that will store a file (image, PDF, etc.)

CREATE TABLE `tbl_file` (
    `id` INT(10),
    `size` FLOAT,
    `name` VARCHAR(45),
    `type` VARCHAR(16),
    `content` BLOB,
    `date_time` TIMESTAMP,
    PRIMARY KEY (`id`) 
)

There are many tables that will have files (tbl_order & tbl_payment) and I want to use only one table to store files (tbl_file). However, some tables may have multiple files for each row.

For example, there are multiple files for one order (invoice, PO, BL, contract) and there may be multiple files for each payment, etc.

So I made the following junction tables for each table that may have multiple files ( I didn't include the foreign key code).

CREATE TABLE `tbl_order_file` (
    `order_id` INT(10),
    `file_id` INT(10),
    PRIMARY KEY (`order_id`, `file_id`),
)

and

CREATE TABLE `tbl_payment_file` (
    `payment_id` INT(10),
    `file_id` INT(10),
    PRIMARY KEY (`payment_id`, `file_id`),
)

the problem here, is that one file can be related to both tables. Maybe it's an advantage rather than a problem but I would like to know if there is a better way to do this or to find a way to restrict the file so it's only referenced in one table.

I am using MySQL with innodb engine.

Was it helpful?

Solution

One way to declare constraint to enforce this for you is to make sure each row in tbl_file is marked as the type of file, either 'O' or 'P' (or other types in the future).

CREATE TABLE `tbl_file` (
    `id` INT(10),
    `file_type` CHAR(1) NOT NULL,  -- must be 'O' or 'P'
    `size` FLOAT,
    `name` VARCHAR(45),
    `type` VARCHAR(16),
    `content` BLOB,
    `date_time` TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY (`id`, `file_type`)
);

Then each subordinate table forces all its rows to be marked with the respective type. Therefore a row in tbl_order_file can reference only rows in tbl_file that have the same file_type:

CREATE TABLE `tbl_order_file` (
    `order_id` INT(10),
    `file_id` INT(10),
    `file_type` CHAR(1) NOT NULL, -- must be 'O'
    PRIMARY KEY (`order_id`, `file_id`),
    FOREIGN KEY (`file_id`, `file_type`) REFERENCES `tbl_file` (`id`, `file_type`)
);

And likewise for tbl_payment_file:

CREATE TABLE `tbl_payment_file` (
    `payment_id` INT(10),
    `file_id` INT(10),
    `file_type` CHAR(1) NOT NULL, -- must be 'P'
    PRIMARY KEY (`payment_id`, `file_id`),
    FOREIGN KEY (`file_id`, `file_type`) REFERENCES `tbl_file` (`id`, `file_type`)
);

One difficulty in MySQL particularly is that MySQL doesn't support CHECK constraints to allow the table definitions to restrict the value of file_type. You'd have to do it in a trigger or with application code.


Re your comment:

Let's say I want to go with my solution without having file_type, what would be an issue in the future?

Well, as you already stated in your original question, without some constraint, there's nothing preventing one row in the file table from being referenced by multiple junction tables, and you could end up with data that is an anomaly for your application.

On the other hand, you might want to allow that flexibility, if a given file pertains to both an order and a payment. If you had no ability to maintain the multiple references, you'd then have to make duplicate copies of such files to allow them to be in multiple categories.

One more issue: none of these solutions prevents your app from inserting a row in the file table that is childless; i.e. a file that has no references from any junction table.

OTHER TIPS

First of all: if you have many-to-one relations between tables, then don't create a primary key on order_id. I would put all files into one table (tbl_file) and add two foreign key fields to the table: order_id and payment_id, which would reference to the respective entry in the payment or order table.

So an entries (in case of one payment having more then one file) would look like:

id  payment_id  order_id    size    name        type        content     date_time
1   1           null        434     File.txt    text/plain  <blob>      24.11.2012
2   1           null        131     File2.txt   text/plain  <blob>      24.11.2012
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top