Para esta pregunta, considere una aplicación que use una base de datos multitiende con modelado de fabricantes y modelos. Si hablamos de autos, entonces los fabricantes serían Ford, Chevrolet, BMW, etc. y los modelos serían F-150, Camaro y M3.Estructura de la base de datos maestros para datos maestros selectivamente anulada por cliente
La relación del modelo al fabricante es de una a una. Los datos para cada inquilino se separan usando un id_cliente.
Requisitos para el modelo de datos:
- Los fabricantes y los modelos se puede definir a nivel de maestría para que estén disponibles para todos los clientes
- al cliente seleccionar cuál de las entidades maestras que les gustaría usar
- Los clientes pueden anular los atributos de un modelo maestro o fabricante
- Los clientes pueden crear sus propios fabricantes
- Los clientes pueden crear sus propios modelos para su propio fabricante o uno maestro
- Otras entidades en el modelo estarán relacionadas con estas entidades por lo que es deseable que exista una tabla principal para cada una de las cuales se pueda crear una clave externa. Las tablas de fabricantes y modelos cumplen esa función en el ejemplo.
En este ejemplo:
- cliente 1 utiliza Ford como está, anula Chevrolet, y añade dos fabricantes personalizados
- cliente 1 utiliza Chevrolet y BMW como está y añade un fabricante de encargo
- modelos se crean de acuerdo con los comentarios en el guión
continuación se muestra un ejemplo de implementación anotado que cumpla con todos los requi rements.
- ¿Cómo se puede mejorar esto?
- ¿De qué otras maneras podrían modelarse estas relaciones?
Tablas Fabricante
/*
* 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');
Tablas Modelo
/*
* 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 */
Vistas para simplificar el uso de estas tablas
/*
* 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;
Fabricantes para 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
Fabricantes para 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
Modelos para 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
Modelos para 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
¿Puede aclarar cómo funcionaría esto? No lo entiendo del todo. Un ejemplo completo de la estructura para los fabricantes sería genial. Tratando de resolverlo obtengo lo siguiente, pero no creo que sea de lo que estás hablando. FABRICANTE-CODE (mfg_id (PK), código) FABRICANTE-DETALLES (mfg_id, (FK, PK), customer_id (PK), attr1, attr) FABRICANTES-TYPE-CODE (mfg_id (FK, PK) , is_master) – cope360
¿Cómo funciona customer_id como columna no nula de FABRICANTES-DETALLES? En el ejemplo, lo tiene configurado en 1 para un tipo MASTER, pero los tipos MASTER deben estar disponibles para todos los clientes. – cope360
No nulo significa que la columna no puede tener nulos, lo que significa que en este caso no podría tener un registro en DETALLES DEL FABRICANTE sin una IDENTIFICACIÓN DEL CLIENTE asociada. El valor MASTER es una clave externa (de ahí la abreviatura fk) de la tabla CÓDIGO DE TIPO DE FABRICANTE: es una clave natural, no usa un número para identificarla. Dicho esto, no hay límite en el modelo de datos actual para limitar qué clientes ver qué tipo de CÓDIGO DE FABRICANTE registra. Si quisiera esto, necesitaría agregar una tabla entre MANUFACTURER-TYPE-CODE y CUSTOMER usando un combo de pk de cualquier tabla como pk. –