I have the following schema. How do I ensure that all values in child are unique for a given child.group_id, child.type, and parent.status? Please note the 1-to-1 relationship between parent and child. If parent and child was one table, a simple UNIQUE index would work, however, I wish to keep the two tables separate. Ideally, stored procedures wouldn't be used, however, I am open to them if necessary. I am using the latest version of MySQL. Thank you
CREATE TABLE IF NOT EXISTS group (
id INT NOT NULL AUTO_INCREMENT ,
moreData VARCHAR(45) NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS parent (
id INT NOT NULL AUTO_INCREMENT ,
status VARCHAR(45) NOT NULL ,
moreData VARCHAR(45) NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS child (
parent_id INT NOT NULL ,
group_id INT NOT NULL ,
type INT NOT NULL ,
moreData VARCHAR(45) NULL ,
PRIMARY KEY (parent_id) ,
INDEX fk_child_group1_idx (group_id ASC) ,
CONSTRAINT fk_child_parent
FOREIGN KEY (parent_id )
REFERENCES parent (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_child_group1
FOREIGN KEY (group_id )
REFERENCES group (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
I think you're looking for something along these lines.
Create an overlapping constraint in "parent". (The column "id" is unique, so {id, any-other-column} must also be unique.)
CREATE TABLE IF NOT EXISTS parent (
id INT NOT NULL AUTO_INCREMENT ,
status VARCHAR(45) NOT NULL ,
moreData VARCHAR(45) NULL ,
PRIMARY KEY (id),
UNIQUE (id, status)
)
ENGINE = InnoDB;
Add the status column in "child".
CREATE TABLE IF NOT EXISTS child (
parent_id INT NOT NULL ,
parent_status VARCHAR(45) NOT NULL ,
group_id INT NOT NULL ,
type INT NOT NULL ,
moreData VARCHAR(45) NULL ,
Primary key constraint doesn't have to change.
PRIMARY KEY (parent_id) ,
INDEX fk_child_group1_idx (group_id ASC) ,
Reference the pair of columns.
CONSTRAINT fk_child_parent
FOREIGN KEY (parent_id, parent_status )
REFERENCES parent (id, status )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_child_group1
FOREIGN KEY (group_id )
REFERENCES group (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION) ,
Whether you ought to cascade updates in fk_child_parent is application-dependent. Give that some thought.
And add a unique constraint on the set of columns you say should be unique.
CONSTRAINT uq_child
UNIQUE (group_id, type, parent_status)
REFERENCES group (id))
ENGINE = InnoDB;
One option is to create before insert trigger to do this verification, check constraints are not supported by mysql so that's not an option.
Related
I have 2 different tables: Profile and Transaction
Profile consists of: pID, firstName, lastName, phoneNumb
Transaction consists of: transID, sellerID, buyerID, itemID
My question is:
How to make sure that both sellerID and buyerID act as a foreign key in reference to profileID in Profile table?
My current code right now:
CREATE TABLE PROFILE
(
pID INT NOT NULL AUTO_INCREMENT ,
firstName VARCHAR(20) NOT NULL ,
lastName INT(20) NOT NULL ,
phoneNumb INT NOT NULL ,
PRIMARY KEY (pID)
) ENGINE = InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE TRANSACTION
(
tID INT NOT NULL AUTO_INCREMENT ,
sellerID INT ,
buyerID INT,
itemID INT,
PRIMARY KEY (tID),
FOREIGN KEY (sellerID, buyerID) REFERENCES PROFILE(pID),
FOREIGN KEY (itemID) REFERENCES ITEM (itemID)
) ENGINE = InnoDB DEFAULT CHARSET=latin1;
I tried this and it gave me this kind of error
1239 - Incorrect foreign key definition for 'foreign key without name': Key reference and table reference don't match
Thanks.
I would go about it this way:
CREATE TABLE TRANSACTION
(
tID INT NOT NULL AUTO_INCREMENT,
sellerID INT,
buyerID INT,
itemID INT,
PRIMARY KEY (tID),
CONSTRAINT fk1 FOREIGN KEY (sellerID) REFERENCES PROFILE(pID)
CONSTRAINT fk2 FOREIGN KEY (buyerID) REFERENCES PROFILE(pID)
CONSTRAINT itemKey FOREIGN KEY (itemID) REFERENCES ITEM (itemID)
) ENGINE = InnoDB DEFAULT CHARSET=latin1;
This assumes that a table called ITEM exists which has a primary key called itemID. Your original problem mentioned only two tables. If ITEM does not exist, then either create it or remove the foreign key constraint from TRANSACTION.
I have the following tables:
CREATE TABLE `OBL2`.`item` (
`itemID` INT NOT NULL AUTO_INCREMENT ,
`itemName` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`itemID`) ,
INDEX `itemName` (`itemName` ASC) );
CREATE TABLE `OBL2`.`subject` (
`subjectID` INT NOT NULL ,
`subjectName` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`subjectID`) );
Now since the connection is many to many, each item can have many subject and each subject can be related to many items - I'd like to set a connection table.
This is my code:
CREATE TABLE `OBL2`.`itemsubjects` (
`itemID` INT NOT NULL ,
`subjectID` INT NOT NULL ,
PRIMARY KEY (`itemID`, `subjectID`) ,
INDEX `itemID_idx` (`itemID` ASC) ,
INDEX `subjectID_idx` (`subjectID` ASC) ,
CONSTRAINT `itemID`
FOREIGN KEY (`itemID` )
REFERENCES `OBL2`.`item` (`itemID` )
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `subjectID`
FOREIGN KEY (`subjectID` )
REFERENCES `OBL2`.`subject` (`subjectID` )
ON DELETE CASCADE
ON UPDATE CASCADE);
but for some reason the code of the 3rd table is not being accepted.
I get an error message:
ERROR 1005: Can't create table 'obl2.itemsubjects' (errno: 121)
I've read about the error on the internet and it says it's a known issue of MYSQL yet there are no solutions.
Any thoughts?
The MySQL docs say in FOREIGN KEY Constraints (emphasis mine):
If the CONSTRAINT symbol clause is given, the symbol value must be unique in the database. If the clause is not given, InnoDB creates the name automatically.
So, the reason that the itemsubject table creation failed, was that you had another (foreign key) constraint, named itemID, or one named subjectID in some other table of the database.
It's good to have a naming conevntion that is standard across the database. Just as you have ColumnName_idx for indices, you can use ReferencedTable_ReferencingTable_FK for foreign key constraints:
CREATE TABLE OBL2.itemsubjects (
itemID INT NOT NULL ,
subjectID INT NOT NULL ,
PRIMARY KEY
(itemID, subjectID) ,
INDEX itemID_idx -- I like these
(itemID ASC) ,
INDEX subjectID_idx -- two
(subjectID ASC) ,
CONSTRAINT item_itemsubject_FK -- what I propose, here
FOREIGN KEY (itemID)
REFERENCES OBL2.item (itemID)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT subject_itemsubject_FK -- and here
FOREIGN KEY (subjectID)
REFERENCES OBL2.subject (subjectID)
ON DELETE CASCADE
ON UPDATE CASCADE
);
I'm fairly new in Mysql, but I have problem that I cannot solve. I will give you an example to demonstrate it. Please note that I know that (for current example) there are other simpler and more efficient ways to solve it... but just take it as an example of the required procedure.
First the data: The data would be the name of a Person.
CREATE TABLE person(
id INT,
name VARCHAR(100)
) TYPE=innodb;
Second: Group Creation... So this is fairly simple... and could easily done using a table 'group' with a foreignkey to person. These groups could be arbitrary, containing any number of persons, duplicated... or not... (that is simple!!)
Third: MY REAL PROBLEM--- I also would like to have Groups that have other Groups as elements (instead of persons). This is where a really get stuck, because I know how to create a groups of persons, a group of groups (having a self-referencing foreign key)... but I don't know how to create a group that MAY HAVE persons AND Groups.
I appreciate any suggestion to solve this issue.
Thank you very much for your comments.
Regards
ACombo
I'd go with firstly setting up the myGroup and person tables.
Secondly, I'd set up a myGroupGroup table with columns myGroupId, parentMyGroupId. This will allow you to relate group rows to child group rows i.e. "this group has these groups within it". If a group has no rows in this table then it has no child groups within it.
Thirdly, I'd set up a personGroup table with columns personId, myGroupId. This will allow you to relate person rows to a given group. If a group has no rows in this table then it has no persons within it.
CREATE TABLE person(
id INT UNSIGNED PRIMARY KEY,
name VARCHAR(100)
) ENGINE=innodb;
CREATE TABLE myGroup(
id INT UNSIGNED PRIMARY KEY,
groupName VARCHAR(100)
) ENGINE=innodb;
-- Holds groups within groups
CREATE TABLE myGroupGroup(
id INT UNSIGNED PRIMARY KEY,
myGroupId INT UNSIGNED,
parentMyGroupId INT UNSIGNED DEFAULT NULL,
CONSTRAINT `fk_myGroupGroup_group1` FOREIGN KEY (`parentMyGroupId`) REFERENCES `myGroup` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_myGroupGroup_group2` FOREIGN KEY (`myGroupId`) REFERENCES `myGroup` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=innodb;
-- Holds persons within a group
CREATE TABLE personGroup(
id INT,
personId int UNSIGNED NOT NULL,
myGroupId int UNSIGNED NOT NULL,
CONSTRAINT `fk_personGroup_group1` FOREIGN KEY (`myGroupId`) REFERENCES `myGroup` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_personGroup_person1` FOREIGN KEY (`personId`) REFERENCES `person` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=innodb;
I've tweaked your SQL a bit:
1) Replaced TYPE with ENGINE
2) Replaced table name group with myGroup (GROUP is a reserved word)
Good luck!
Alternative:
CREATE TABLE Entity
( EntityId INT --- this id could be AUTO_INCREMENT
, PRIMARY KEY (EntityId)
) ENGINE = InnoDB ;
CREATE TABLE Person
( PersonId INT --- but not this id
, PersonName VARCHAR(100)
, PRIMARY KEY (PersonId)
, FOREIGN KEY (PersonId)
REFERENCES Entity(EntityId)
) ENGINE = InnoDB ;
CREATE TABLE Grouping
( GroupingId INT --- and neither this id
, GroupingName VARCHAR(100)
, PRIMARY KEY (GroupingId)
, FOREIGN KEY (GroupingId)
REFERENCES Entity(EntityId)
) ENGINE = InnoDB ;
CREATE TABLE Belongs
( EntityId INT
, GroupingID INT
, PRIMARY KEY (EntityId, GroupingId)
, FOREIGN KEY (EntityId)
REFERENCES Entity(EntityId)
, FOREIGN KEY (GroupingID)
REFERENCES Grouping(GroupingId)
) ENGINE = InnoDB ;
I'm running the following MySQL query (trimmed down), generated automatically by MySQL Workbench and I get the following error:
Error Code: 1005
Can't create table 'regula.reservation' (errno: 121)
I'm not very proficient with databases and this error is not very informative.
What is the problem here?
-- -----------------------------------------------------
-- Table `regula`.`Users`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `regula`.`Users` ;
CREATE TABLE IF NOT EXISTS `regula`.`Users` (
`idUsers` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` TEXT NOT NULL ,
`type` TEXT NOT NULL ,
`pwd` TEXT NOT NULL ,
PRIMARY KEY (`idUsers`) ,
UNIQUE INDEX `idUsers_UNIQUE` (`idUsers` ASC) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `regula`.`Projects`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `regula`.`Projects` ;
CREATE TABLE IF NOT EXISTS `regula`.`Projects` (
`idProjects` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`ownerId` INT UNSIGNED NOT NULL ,
`name` TEXT NOT NULL ,
`date` DATE NOT NULL ,
`time` TIME NOT NULL ,
`place` TEXT NOT NULL ,
`itemType` INT NOT NULL ,
PRIMARY KEY (`idProjects`) ,
UNIQUE INDEX `idProjects_UNIQUE` (`idProjects` ASC) ,
INDEX `ownerId` (`ownerId` ASC) ,
CONSTRAINT `ownerId`
FOREIGN KEY (`ownerId` )
REFERENCES `regula`.`Users` (`idUsers` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `regula`.`ItemTypes`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `regula`.`ItemTypes` ;
CREATE TABLE IF NOT EXISTS `regula`.`ItemTypes` (
`idItemTypes` INT UNSIGNED NOT NULL ,
`prjId` INT UNSIGNED NOT NULL ,
`parentId` INT UNSIGNED NULL DEFAULT NULL ,
`name` TEXT NOT NULL ,
PRIMARY KEY (`idItemTypes`) ,
INDEX `prjId` (`prjId` ASC) ,
INDEX `parentId` (`parentId` ASC) ,
CONSTRAINT `prjId`
FOREIGN KEY (`prjId` )
REFERENCES `regula`.`Projects` (`idProjects` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `parentId`
FOREIGN KEY (`parentId` )
REFERENCES `regula`.`ItemTypes` (`idItemTypes` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `regula`.`Reservation`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `regula`.`Reservation` ;
CREATE TABLE IF NOT EXISTS `regula`.`Reservation` (
`idReservation` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`prjId` INT UNSIGNED NOT NULL ,
`itemTypeId` INT UNSIGNED NOT NULL ,
`userId` INT UNSIGNED NOT NULL ,
PRIMARY KEY (`idReservation`) ,
INDEX `prjId` (`prjId` ASC) ,
INDEX `itemTypeId` (`itemTypeId` ASC) ,
INDEX `userId` (`userId` ASC) ,
CONSTRAINT `prjId`
FOREIGN KEY (`prjId` )
REFERENCES `regula`.`Projects` (`idProjects` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `itemTypeId`
FOREIGN KEY (`itemTypeId` )
REFERENCES `regula`.`ItemTypes` (`idItemTypes` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `userId`
FOREIGN KEY (`userId` )
REFERENCES `regula`.`Users` (`idUsers` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Error 121 means that there is a foreign key constraint error. Since you're using InnoDB, you can use SHOW ENGINE INNODB STATUS after running the failed query to get an explanation in the LATEST FOREIGN KEY ERROR section. Having run your SQL myself, I get this:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
101210 14:55:50 Error in foreign key constraint creation for table `regula`.`Reservation`.
A foreign key constraint of name `regula`.`prjId`
already exists. (Note that internally InnoDB adds 'databasename'
in front of the user-defined constraint name.)
Note that InnoDB's FOREIGN KEY system tables store
constraint names as case-insensitive, with the
MySQL standard latin1_swedish_ci collation. If you
create tables or databases whose names differ only in
the character case, then collisions in constraint
names can occur. Workaround: name your constraints
explicitly with unique names.
Basically, you need to give your prjId constraint name a unique name in the last table. Constraint/foreign key names are global to a database, so they cannot be reused in different tables. Just change the last
CONSTRAINT `prjId`
to
CONSTRAINT `prjId2`
The error code 121 comes when you try to map the foreign key.
Basically it comes when your foreign key name already exists in the database.
For example:
ALTER TABLE `photokiosk`.`kiosk_event`
ADD CONSTRAINT `event_booking_id`
FOREIGN KEY `event_booking_id` (`event_booking_id`)
REFERENCES `event_booking` (`event_booking_id`)
If foreign key with the name event_booking_id is already mapped with the other table.
To get rid of this issue, please change the foreign key name, not the column name.
You will get this error message if you try to use a constraint name which already exists in the table.
Here 'prjId' already exists in table regula.ItemTypes. So, you can't use the same constraint name on table 'regula.reservation' again.
I'm trying to create a foreign key on two columns of a table to point to the same column of another table, but I seem to get an error...
Here's what I do:
CREATE TABLE test2 (
ID INT NOT NULL AUTO_INCREMENT,
col1 INT NOT NULL,
col2 INT NOT NULL,
PRIMARY KEY (ID),
CONSTRAINT fk FOREIGN KEY (col1, col2)
REFERENCES test1(ID, ID)
ON UPDATE CASCADE
ON DELETE RESTRICT
) ENGINE=InnoDB;
But I get
ERROR 1005 (HY000): Can't create table 'DB.test2' (errno: 150)
If I only have one column, however, the table is correctly created.
Could someone point out to me where the error is?
Thanks
n
Tried it here and got the same error. This works though:
CREATE TABLE test2 (
ID INT NOT NULL AUTO_INCREMENT,
col1 INT NOT NULL,
col2 INT NOT NULL,
PRIMARY KEY (ID),
CONSTRAINT fk FOREIGN KEY (col1)
REFERENCES test1(ID)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk2 FOREIGN KEY (col2)
REFERENCES test1(ID)
ON UPDATE CASCADE
ON DELETE RESTRICT
) ENGINE=InnoDB
Yes, I know - your script should work (even if it doesn't seem to make much sense). Yet, I guess this new version is better.
The problem would appear to be that you are specifying the same parent column twice in the same foreign key (i.e, (ID, ID)). The following should work:
Create Table Test1
(
PK1 int not null
, PK2 int not null
, Primary Key ( PK1, PK2 )
)
Create Table Test2
(
Id int not null Auto_Increment
, PK1 int not null
, PK2 int not null
, Primary Key ( ID )
, Constraint FK_Test2
Foreign Key ( PK1, PK2 )
References Test1( PK1, PK2 )
)
If it is the case, that you want two columns in a child table referencing the same parent table column, then you must add two foreign key references as shown by rsenna as those represent two independent relations.