【问题标题】:Multiple tables referencing one table using multiple junction tables多个表使用多个联结表引用一个表
【发布时间】:2012-11-24 20:22:34
【问题描述】:

我有下表将存储文件(图像、PDF 等)

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

有许多表将包含文件 (tbl_order & tbl_payment),我只想使用一个表来存储文件 (tbl_file)。但是,某些表的每一行可能有多个文件。

例如,一个订单有多个文件(发票、采购订单、提单、合同),每次付款可能有多个文件等。

所以我为每个可能有多个文件的表制作了以下联结表(我没有包括外键代码)。

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

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

这里的问题是一个文件可以与两个表相关。也许这是一个优势而不是一个问题,但我想知道是否有更好的方法来做到这一点,或者找到一种方法来限制文件,以便它只在一个表中引用。

我正在使用带有 innodb 引擎的 MySQL。

【问题讨论】:

    标签: mysql database file innodb junction


    【解决方案1】:

    声明约束以强制执行此操作的一种方法是确保 tbl_file 中的每一行都标记为文件类型,“O”或“P”(或将来的其他类型)。

    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`)
    );
    

    然后每个从属表强制其所有行使用相应的类型进行标记。因此,tbl_order_file 中的一行可以 引用 tbl_file 中具有相同 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`)
    );
    

    对于 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`)
    );
    

    MySQL 中的一个特别困难是 MySQL 不支持 CHECK 约束以允许表定义限制 file_type 的值。您必须在触发器或应用程序代码中执行此操作。


    你的评论:

    假设我想在没有 file_type 的情况下使用我的解决方案,将来会出现什么问题?

    好吧,正如您在原始问题中已经说过的那样,没有任何约束,没有什么可以阻止文件表中的一行被多个联结表引用,并且您最终可能会得到对您的应用程序来说是异常的数据。

    另一方面,如果给定文件既涉及订单又涉及付款,您可能想要允许这种灵活性。如果您无法维护多个引用,则必须复制此类文件以允许它们属于多个类别。

    还有一个问题:这些解决方案都不能阻止您的应用在文件表中插入没有子元素的行;即没有来自 any 联结表的引用的文件。

    【讨论】:

    • 非常感谢这个解决方案。假设我想在没有 file_type 的情况下使用我的解决方案,将来会出现什么问题?
    【解决方案2】:

    首先:如果表之间存在多对一关系,则不要在order_id 上创建主键。 我会将所有文件放入一个表 (tbl_file) 并向表中添加两个外键字段:order_idpayment_id,这将引用 paymentorder 表中的相应条目。

    所以一个条目(如果一笔付款有多个文件)看起来像:

    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
    

    【讨论】:

    • 这称为独占弧。未使用的外键应该为 NULL 而不是 0,因为不能为 0 声明 FK 约束,除非引用的表中有 id 0。
    • 这不是这里的重点,这是对架构的描述。
    • 关于架构,如果添加第三种类型的文件,则需要在tbl_file中添加第三个FK列。
    • 我正在寻找一种灵活的解决方案,当我想要为新表而不是新表创建文件时,不会更改任何表。您如何看待连接表?
    猜你喜欢
    • 2014-11-10
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 1970-01-01
    • 2019-07-11
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多