The*_*tor 5 mysql database-design constraint
我有一个定义关系的表
Src smallint(5) unsigned NOT NULL,
Dst smallint(5) unsigned NOT NULL,
other fields
Run Code Online (Sandbox Code Playgroud)
我需要添加一个约束,说明其中一列中是否存在给定值。
1) 不能在同一列中重复。
2) 也不能在其他列中重复。
这是无效的
src dst
1 354
666 1
Run Code Online (Sandbox Code Playgroud)
由于值 1 出现在第一行中,因此它不能出现在第二行中。
如何定义这种类型的约束?
我正在对应用程序杠杆进行轻量级检查。但我希望数据库确保它。
更新:目前我有 7 种不同类型的关系,每种关系类型一张表。
更新 2:原来这只是一张包含所有关系的表,现在我要爆炸了
# variante
Create TABLE `productsRelationships3` (
`relSrc` smallint(5) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
PRIMARY KEY `src-dst-3` (relSrc, relDst),
UNIQUE `src-3` (relSrc)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# this is the import
INSERT INTO productsRelationships3 SELECT relSrc, relDst FROM productsRelationships WHERE relType=3;
DELETE FROM productsRelationships WHERE relType=3;
#this is the retrieval. The dummy rows are there because I do a UNION
#SELECT relSrc, relDst, 3 as relType, relTypeDesc, 0 as fracQty, 28281 as source FROM productsRelationships3 LEFT JOIN productsRelationshipsDesc on 3=relTypeID WHERE relDst=28281 OR relSrc=28281;
# fraccion
#relType is from the old 1-table schema. It's going to be deleted
Create TABLE `productsRelationships6` (
`relSrc` smallint(5) unsigned NOT NULL,
`relType` tinyint(2) unsigned NOT NULL DEFAULT 6,
`fracQty` int(2) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
PRIMARY KEY `src-dst-6` (relSrc, relDst),
UNIQUE `src-6` (relSrc),
UNIQUE `dst-6` (relDst),
CONSTRAINT `fk_type_desc_6` FOREIGN KEY (`relType`) REFERENCES `productsrelationshipsdesc` (`relTypeID`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#import
INSERT INTO productsRelationships6 SELECT relSrc, relType, fracQty, relDst FROM productsRelationships WHERE relType=6;
Run Code Online (Sandbox Code Playgroud)
其他表与 productsRelationships3 基本相同
我稍微修改了ypercube 的解决方案,以便源和目标都不为空,正如原始设计所保证的那样。我的CHECK约束被注释掉了,因为它们显然在 MySQL 中不起作用。我将它们保留为注释,因为它们记录了我的意图,并且它们将适用于其他 RDBMS。
CREATE TABLE PointType
( PointTypeID tinyint unsigned NOT NULL,
TypeDescription CHAR(20) NOT NULL,
PRIMARY KEY (PointTypeID),
UNIQUE (TypeDescription)
) ;
INSERT INTO PointType
(PointTypeID, TypeDescription)
VALUES
(1, 'Source'),
(2, 'Destination') ;
CREATE TABLE PointUsageQuota
( RouteID int unsigned NOT NULL,
PointTypeID tinyint unsigned NOT NULL,
PointID smallint(5) unsigned NOT NULL,
PRIMARY KEY (PointID), -- and this is what all the fuss is about
UNIQUE (RouteID , PointID, PointTypeID), -- target for the foreign keys
FOREIGN KEY (PointTypeID)
REFERENCES PointType (PointTypeID)
) ;
CREATE TABLE Route
( RouteID int unsigned NOT NULL,
SourcePointID smallint(5) unsigned NOT NULL,
SourceTypeID tinyint unsigned NOT NULL,
-- CHECK(SourceTypeID = 1),
FOREIGN KEY (RouteID , SourcePointID, SourceTypeID)
REFERENCES PointUsageQuota (RouteID , PointID, PointTypeID) ,
DestinationPointID smallint(5) unsigned NOT NULL,
DestinationTypeID tinyint unsigned NOT NULL,
-- CHECK(DestinationTypeID = 2),
FOREIGN KEY (RouteID , DestinationPointID, DestinationTypeID)
REFERENCES PointUsageQuota (RouteID , PointID, PointTypeID) ,
-- other fields
PRIMARY KEY (RouteID)
) ;
Run Code Online (Sandbox Code Playgroud)
测试:
insert into PointUsageQuota
values(1,1,666),(1,2,354);
INSERT INTO Route VALUES (1, 666, 1, 354, 2);
-- this fails:
INSERT INTO Route VALUES (2, 666, 1, 354, 2);
-- this fails too:
INSERT INTO Route VALUES (2, 354, 1, 666, 2);
Run Code Online (Sandbox Code Playgroud)
我认为当前的设计不可能有这种限制。如果您可以更改它并假设表格现在是:
CREATE TABLE Route
( RouteID int unsigned NOT NULL,
Src smallint(5) unsigned NOT NULL,
Dst smallint(5) unsigned NOT NULL,
-- other fields
PRIMARY KEY (RouteID)
) ;
Run Code Online (Sandbox Code Playgroud)
您可以拆分为 2 个表,并将两列移动到新表中,将它们合并为一列 ( SrcDst)。一个只有 2 行的小参考表 ( ) 将有助于强制执行只有 a和 a 的PointType要求:SrcDst
CREATE TABLE Route
( RouteID int unsigned NOT NULL,
--- other fields
PRIMARY KEY (RouteID)
) ;
CREATE TABLE PointType
( PointTypeID tinyint unsigned NOT NULL,
TypeDescription CHAR(20) NOT NULL,
PRIMARY KEY (PointTypeID),
UNIQUE (TypeDescription)
) ;
INSERT INTO PointType
(PointTypeID, TypeDescription)
VALUES
(1, 'Source'),
(2, 'Destination') ;
CREATE TABLE RoutePoint
( RouteID int unsigned NOT NULL,
PointTypeID tinyint unsigned NOT NULL,
SrcDst smallint(5) unsigned NOT NULL,
PRIMARY KEY (RouteID, PointTypeID),
UNIQUE (SrcDst), -- and this is what all the fuss is about
FOREIGN KEY (RouteID)
REFERENCES Route (RouteID)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (PointTypeID)
REFERENCES PointType (PointTypeID)
) ;
Run Code Online (Sandbox Code Playgroud)
这意味着旧Route表中的任何行现在将成为新表中的 1 行Route和表中的 2 行RoutePoint。
这意味着现在你不能简单地INSERT进入Route表中。您必须使用一个事务来确保如果在Route表中插入一行,则也会在RoutePoint表中插入 2 行。Route否则,您可能会有没有Src或 的行Dst。
必须对两个表的UPDATE和DELETE语句进行类似的更改,因此不会意外更改或从RoutePoint表中删除行,例如留下Route没有相关Src或Dst数据的行。