patternsqlMinor
MySQL unique constraint across two columns
Viewed 0 times
uniquecolumnsconstraintmysqltwoacross
Problem
I have a table defining relationships
I need to add a constraint that says if a given values is present in one of the columns, then.
1) Cannot be duplicated in the same column.
2) Cannot be duplicated in the other column either.
This is invalid
Since the value 1 is present in the first row, it cannot be present in the second row.
How can I define this type of constraint?
I'm doing a lightweight check at application lever. But I want the DB to ensure it.
Update: Currently I have 7 different types of relationships, and one table per relationship type.
Update 2: Originally this was only one table containing all the relationships, now I'm exploding it
``
Src smallint(5) unsigned NOT NULL,
Dst smallint(5) unsigned NOT NULL,
other fieldsI need to add a constraint that says if a given values is present in one of the columns, then.
1) Cannot be duplicated in the same column.
2) Cannot be duplicated in the other column either.
This is invalid
src dst
1 354
666 1Since the value 1 is present in the first row, it cannot be present in the second row.
How can I define this type of constraint?
I'm doing a lightweight check at application lever. But I want the DB to ensure it.
Update: Currently I have 7 different types of relationships, and one table per relationship type.
Update 2: Originally this was only one table containing all the relationships, now I'm exploding it
``
# 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 DELETESolution
I have modified ypercube's solution a little bit, so that both source and destination are not null, as is guaranteed by the original design. My
Testing:
CHECK constraints are commented out, as they apparently will not work in MySQL. I kept them as comments because they document my intent, and they will work on other 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)
) ;Testing:
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);Code Snippets
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)
) ;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);Context
StackExchange Database Administrators Q#29336, answer score: 5
Revisions (0)
No revisions yet.