每个客户有选择地覆盖主数据的数据库结构

时间:2009-07-17 23:14:01

标签: sql database data-modeling

对于这个问题,请考虑使用多租户数据库的应用程序以及制造商和模型的建模。如果我们谈论汽车,那么制造商将是福特,雪佛兰,宝马等,而型号将是F-150,Camaro和M3。

模型与制造商的关系是多对一的。使用customer_id分隔每个租户的数据。

数据模型的要求:

  • 制造商和模型可以在主级别定义,以便所有客户都可以使用
  • 客户选择他们想要使用的主要实体
  • 客户可以覆盖主模型或制造商的属性
  • 客户可以创建自己的制造商
  • 客户可以为自己或主制造商创建自己的模型
  • 模型中的其他实体将与这些实体相关,因此希望每个实例都有一个主表可以进行外键。制造商和模型表填充了该示例中的角色。

在这个例子中:

  • 客户1使用福特原样,覆盖雪佛兰,并增加两个定制制造商
  • 客户1按原样使用雪佛兰和宝马,并添加一个定制制造商
  • 根据脚本
  • 中的注释创建模型

以下是符合所有要求的带注释的示例实现。

  • 如何改进?
  • 这些关系可以用什么方式建模?

制造商表格

/*
 * Master manufacturers shared between all customers
 */
CREATE TABLE master_manufacturers (
    master_manufacturer_id INTEGER NOT NULL,
    name VARCHAR(100) NOT NULL,
    attribute_1 VARCHAR(50),
    /* ... */
    attribute_n VARCHAR(50),
    PRIMARY KEY (master_manufacturer_id)
);

INSERT INTO
    master_manufacturers (master_manufacturer_id, name)
VALUES
    (1, 'Ford'),
    (2, 'Chevrolet'),
    (3, 'BMW');

/*
 * A Customer's manufacturer.  
 *   If master_manufacturer_id IS NULL, then it is a custom manufacturer and manufacturer_custom contains the data
 *   If master_manufacturer_id IS NOT NULL and manufacturer_custom does not exist, then the master is used without modification
 *   If master_manufacturer_id IS NOT NULL and manufacturer_custom exists, then the master is overridden
 */
CREATE TABLE manufacturers (
    manufacturer_id INTEGER NOT NULL,
    customer_id INTEGER NOT NULL,
    master_manufacturer_id INTEGER,
    PRIMARY KEY (manufacturer_id),
    FOREIGN KEY (master_manufacturer_id) REFERENCES master_manufacturers (master_manufacturer_id),
    UNIQUE (customer_id, master_manufacturer_id)
);

INSERT INTO
    manufacturers (manufacturer_id, customer_id, master_manufacturer_id)
VALUES
    (1, 1, 1),
    (2, 1, 2),
    (3, 1, NULL),
    (4, 1, NULL),
    (5, 2, 2),
    (6, 2, 3),    
    (7, 2, NULL);    

CREATE TABLE manufacturer_custom (
    manufacturer_id INTEGER NOT NULL,
    name VARCHAR(100) NOT NULL,
    attribute_1 VARCHAR(50),
    /* ... */
    attribute_n VARCHAR(50),
    PRIMARY KEY (manufacturer_id),
    FOREIGN KEY (manufacturer_id) REFERENCES manufacturers (manufacturer_id)
);

INSERT INTO
    manufacturer_custom (manufacturer_id, name)
VALUES
    (2, 'Chevy'),
    (3, 'Cust 1 Custom 1'),
    (4, 'Cust 1 Custom 2'),
    (7, 'Cust 2 Custom 1');

模型表

/*
 * Master models shared between all customers
 */
CREATE TABLE master_models (
    master_model_id INTEGER NOT NULL,
    master_manufacturer_id INTEGER NOT NULL,
    name VARCHAR(100) NOT NULL,
    attribute_1 VARCHAR(50),
    /* ... */
    attribute_n VARCHAR(50),
    PRIMARY KEY (master_model_id),
    FOREIGN KEY (master_manufacturer_id) REFERENCES master_manufacturers (master_manufacturer_id)
);

INSERT INTO
    master_models (master_model_id, master_manufacturer_id, name)
VALUES
    (1, 1, 'F-150'),
    (2, 1, 'F-250'),
    (3, 1, 'Falcon'),
    (4, 2, 'Camaro'),
    (5, 2, 'Corvette'),
    (6, 3, 'M3'),
    (7, 3, '135i');

/*
 * A Customer''s model.  
 *   If master_model_id IS NULL, then it is a custom model and model_custom contains the data
 *   If master_model_id IS NOT NULL and model_custom does not exist, then the master is used without modification
 *   If master_model_id IS NOT NULL and model_custom exists, then the master is overridden
 */
CREATE TABLE models (
    model_id INTEGER NOT NULL,
    master_model_id INTEGER,
    manufacturer_id INTEGER NOT NULL,
    attribute_1 VARCHAR(50),
    /* ... */
    attribute_n VARCHAR(50),
    PRIMARY KEY (model_id),
    FOREIGN KEY (master_model_id) REFERENCES master_models (master_model_id)
);

INSERT INTO
    models (model_id, master_model_id, manufacturer_id)
VALUES
    (1, 1, 1),    /* F-150 for customer_1's Ford */
    (2, 2, 1),    /* F-250 for customer_1's Ford */
    (3, 4, 2),    /* Camaro for customer_1's Chevy */
    (4, 4, 5),    /* Camaro for customer_2's Chevrolet */
    (5, 5, 5),    /* Corvette for customer_2's Chevrolet */
    (6, 6, 6),    /* M3 for customer_2's BMW */
    (7, NULL, 1), /* F-350 (custom) for customer_1's Ford */
    (8, NULL, 6), /* M7 (custom) for customer_2's BMW */
    (9, NULL, 7); /* Custom Model (custom) for customer_2's Custom Mfg */

CREATE TABLE model_custom (
    model_id INTEGER NOT NULL,
    name VARCHAR(100) NOT NULL,
    attribute_1 VARCHAR(50),
    /* ... */
    attribute_n VARCHAR(50),
    PRIMARY KEY (model_id),
    FOREIGN KEY (model_id) REFERENCES models (model_id)
);

INSERT INTO
    model_custom (model_id, name)
VALUES
    (7, 'F-350'),        /* F-350 for customer_1's Ford */
    (8, 'M7'),           /* M7 for customer_2's BMW */
    (9, 'Custom Model'); /* Custom Model for customer_2's Custom Mfg */

简化使用这些表格的观点

/*
 * View for a customer''s manufacturers
 */
CREATE VIEW vw_manufacturers AS
    SELECT
        m.customer_id,
        m.manufacturer_id, 
        COALESCE(cm.name, mm.name) AS name,
        COALESCE(cm.attribute_1, mm.attribute_1) AS attribute_1,
        /* ... */
        COALESCE(cm.attribute_n, mm.attribute_n) AS attribute_n
    FROM
        manufacturers m
    LEFT JOIN
        master_manufacturers mm
    USING
        (master_manufacturer_id)
    LEFT JOIN
        manufacturer_custom cm
    USING
        (manufacturer_id);

/*
 * View for a customer's models
 */
CREATE VIEW vw_models AS
    SELECT
        mfg.customer_id,
        mfg.manufacturer_id,
        mfg.name AS manufacturers_name,
        m.model_id,
        COALESCE(cm.name, mm.name) AS name,
        COALESCE(cm.attribute_1, mm.attribute_1) AS attribute_1,
        /* ... */
        COALESCE(cm.attribute_n, mm.attribute_n) AS attribute_n
    FROM
        vw_manufacturers mfg,
        models m
    LEFT JOIN
        master_models mm
    USING
        (master_model_id)
    LEFT JOIN
        model_custom cm
    USING
        (model_id)
    WHERE
        mfg.manufacturer_id = m.manufacturer_id;

customer_id 1的制造商

SELECT manufacturer_id, name FROM vw_manufacturers WHERE customer_id = 1;

 manufacturer_id |      name       
-----------------+-----------------
           1 | Ford
           2 | Chevy
           3 | Cust 1 Custom 1
           4 | Cust 1 Custom 2

customer_id 2的制造商

SELECT manufacturer_id, name FROM vw_manufacturers WHERE customer_id = 2;

 manufacturer_id |      name       
-----------------+-----------------
           5 | Chevrolet
           6 | BMW
           7 | Cust 2 Custom 1

customer_id 1的模型

SELECT * FROM vw_models WHERE customer_id = 1;

 customer_id | manufacturer_id | manufacturers_name | model_id |  name  
-------------+-----------------+--------------------+----------+--------
       1 |               1 | Ford               |        1 | F-150
       1 |               1 | Ford               |        2 | F-250
       1 |               2 | Chevy              |        3 | Camaro
       1 |               1 | Ford               |        7 | F-350

customer_id 2的模型

SELECT * FROM vw_models WHERE customer_id = 2;

 customer_id | manufacturer_id | manufacturers_name | model_id |     name     
-------------+-----------------+--------------------+----------+--------------
           2 |               5 | Chevrolet          |        4 | Camaro
           2 |               5 | Chevrolet          |        5 | Corvette
           2 |               6 | BMW                |        6 | M3
           2 |               6 | BMW                |        8 | M7
           2 |               7 | Cust 2 Custom 1    |        9 | Custom Model

2 个答案:

答案 0 :(得分:2)

您需要以下表格:

  • 制造商-CODE
  • 制造商-TYPE-CODE
  • 制造商详情
  • 模型的代码
  • 模型-TYPE-CODE
  • MODEL-详情

如果您的表具有相同的数据 - 您需要合并它们,并使用TYPE_CODE表来区分它们。

回复:制造商&顾客 目前,您需要PK为MANUFACTURER-ID和CUSTOMER-ID。最好将制造商分为制造商 - 代码和制造商 - 详细信息。 MANUFACTURER-CODE将包含“BMW”,“FORD”等以及定制。 MANUFACTURER-DETAILS允许您按客户保留详细数据,同时允许您重复使用“BMW”等等的代码。模型也是如此。

下一步是为引擎,车轮等事物定义TYPE-CODE表。我使用名为MODEL-ATTRIBUTES的XREF表将这些表与MODEL-DETAILS相关联。 MODEL-ATTRIBUTES表包含:

  • MODEL-DETAILS-ID(pk)
  • MODEL-ATTRIBUTE-TYPE-CODE(pk)
  • ATTRIBUTE-CODE(pk)

这将允许可选的模型属性与适用的MODEL-DETAILS记录相关联,而无需不断向MODEL-DETAILS表添加属性。

<强>制造商代码

  • MANUFACTURER-CODE VARCHAR(4)(pk)
  • 说明
  • EFFECTIVE-DATE not null
  • EXPIRY-DATE非空

MANUFACTURER-CODE |描述|有效日期| EXPIRY-DATE
福特|福特| 01-01-1900 | 12-31-9999
宝马|宝马| 01-01-1900 | 12-31-9999
CHEV |雪佛兰| 01-01-1900 | 12-31-9999

<强>制造商-TYPE-CODE

  • MANUFACTURER-TYPE-CODE(pk)
  • DESCRIPTION not null

MANUFACTURER-TYPE-CODE |说明
MASTER |主
CUSTOM |定制

<强>制造商详情

  • MANUFACTURER-DETAILS-ID(pk)
  • MANUFACTURER-CODE(fk)not null
  • MANUFACTURER-TYPE-CODE(fk)not null
  • CUSTOMER-ID(fk)not null

MANUFACTURER-DETAILS-ID |制造商代码|制造商类型代码|客户ID
1 |宝马| MASTER | 1
2 |宝马| CUSTOM | 1

MODEL

  • MODEL-ID(pk)
  • MANUFACTURER-DETAILS-ID(fk)not null
  • DESCRIPTION not null

MODEL-ID | MANUFACTURER-DETAILS-ID |说明
1 | 1 | M3
1 | 2 | M3降低了

答案 1 :(得分:-2)

这取决于该系统的使用。 您可以针对OLAP与OLTP进行不同的设计。

从理论上讲,这可能都在一张桌子上......