【发布时间】:2021-09-26 08:46:44
【问题描述】:
今年我一直在学习关系数据库以及如何设计它们。为了加强我的知识,我正在尝试使用 Python 和 sqlite3 设计和实现一个数据库。
该数据库是关于一家纺织公司的,除其他外,他们希望保留以下信息:
- 他们用于制造产品的材料
- 寻找材料的商店
- 一些商店(他们确实购买材料的商店)被视为供应商。
- 他们想知道哪些供应商提供哪些材料
关于这最后一个关系,有一些限制:
- 供应商可以提供不止一种材料(供应商类最大基数很多)
- 一种材料可以由多个供应商提供(材料类别最大基数很多)
- 所有材料必须由至少一个供应商提供(材料类别最小基数之一)
- 所有供应商必须提供至少一种材料(供应商等级最低基数之一)
这就是我认为 ER 图给出这些指示的方式:
Entity-Relation diagram for "Provides" relationship
鉴于最小基数之一,我认为我必须通过触发器实现完整性限制。这就是我认为逻辑设计(数据库中的实际表)的样子:
Logical diagram for "Provides" relationship
具有以下完整性限制:
IR1。 Material-Provides 中的最小基数之一: Material 表中的“cod_material”属性的每个值必须作为 中的“cod_material”属性的值至少出现一次提供表格。
IR2。 Supplier-Provides 中的最小基数: Supplier 表中“cod_supplier”属性的每个值必须作为 中“cod_supplier”属性的值至少出现一次提供表格。
所有这一切意味着,在插入新的供应商或材料时,我还必须插入他们提供的材料(在供应商的情况下)或供应商提供的材料(在材料的情况下)。
这是我考虑完整性限制的触发器的样子(我还应该补充一点,我一直在使用 pl-sql,而 sqlite 使用 sql,所以我不习惯这种语法,可能会有一些错误):
CREATE TRIGGER IF NOT EXISTS check_mult_provides_supl
AFTER INSERT ON Supplier
BEGIN
SELECT
CASE WHEN ((SELECT p.cod_supplier FROM Provides p WHERE p.cod_supplier = new.cod_supplier) IS NULL)
THEN RAISE(ABORT, 'Esta tienda no ha provisto aun ningun material')
END;
END;
CREATE TRIGGER IF NOT EXISTS check_mult_provides_mat
AFTER INSERT ON Material
BEGIN
SELECT
CASE WHEN ((SELECT m.cod_material FROM Material m WHERE m.cod_material = new.cod_material) IS NULL)
THEN RAISE(ABORT, 'Este material no ha sido provisto por nadie')
END;
END;
我已尝试分别向 Material 和 Supplier 表添加新行,并且触发器正在工作(或者至少它们不允许我插入新的提供表中没有行的行)。
这是我遇到僵局的时候:
如果数据库为空,如果我尝试在 Material 或 Supplier 表中插入一行,触发器会触发并且它们不允许我(因为首先我需要在表中插入相应的行提供)。但是,如果我尝试在 Provides 表中插入一行,则会出现外键约束错误(显然,因为该供应商和材料尚未插入各自的表中),所以基本上我不能在我的数据库中插入行。
我能想到的唯一答案不是很令人满意:暂时禁用任何约束(外键约束或触发器的完整性)会使数据库完整性面临风险,因为新插入的行不会触发触发器即使这个之后启用。我想到的另一件事是放宽最小基数限制,但我假设与最小基数的多对多关系,一个限制在真实数据库中应该是常见的,所以必须有另一种解决方案。
我怎样才能摆脱这个僵局?也许一个过程(虽然 sqlite 没有存储过程,但我想我可以通过 sqlite3 模块中的 create_function() 使用 Python API 来制作它们)可以解决问题?
以防万一,如果有人想重现这部分数据库,这里是创建表的代码(我最后决定自动递增主键,所以数据类型是整数,而不是 ER图和表示数据类型字符的逻辑图)
CREATE TABLE IF NOT EXISTS Material (
cod_material integer AUTO_INCREMENT PRIMARY KEY,
descriptive_name varchar(100) NOT NULL,
cost_price float NOT NULL
);
CREATE TABLE IF NOT EXISTS Shop (
cod_shop integer AUTO_INCREMENT PRIMARY KEY,
name varchar(100) NOT NULL,
web varchar(100) NOT NULL,
phone_number varchar(12),
mail varchar(100),
address varchar(100)
);
CREATE TABLE IF NOT EXISTS Supplier (
cod_proveedor integer PRIMARY KEY CONSTRAINT FK_Supplier_Shop REFERENCES Shop(cod_shop)
);
CREATE TABLE IF NOT EXISTS Provides (
cod_material integer CONSTRAINT FK_Provides_Material REFERENCES Material(cod_material),
cod_supplier integer CONSTRAINT FK_Provides_Supplier REFERENCES Supplier(cod_supplier),
CONSTRAINT PK_Provides PRIMARY KEY (cod_material, cod_supplier)
);
【问题讨论】:
标签: sql sqlite database-design triggers cardinality