Problem with foreign key constraints and construction of Mysql DB - mysql

I'm having a problem with thinking of the way to connect two tables.
I have one table with actions (RAD):
CREATE TABLE RAD (
rad_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
spec_id INT NULL,
predp_id INT NULL,
predf_id INT NULL,
strp_ID INT NULL,
strf_ID INT NULL,
---more fileds---
FOREIGN KEY (spec_id) REFERENCES SPEC(spec_id) ON DELETE SET NULL,
FOREIGN KEY (strp_ID) REFERENCES STRANKEP(strp_ID) ON DELETE CASCADE,
FOREIGN KEY (strf_ID) REFERENCES STRANKEF(strf_ID) ON DELETE CASCADE,
FOREIGN KEY (predp_id) REFERENCES PREDMETIP(predp_id) ON DELETE CASCADE,
FOREIGN KEY (predf_id) REFERENCES PREDMETIF(predf_id) ON DELETE CASCADE
) ENGINE=InnoDB COLLATE utf8_general_ci;
And one table of specifications (SPEC) based on whom bill will be made:
CREATE TABLE SPEC (
spec_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
---more fileds---
) ENGINE=InnoDB COLLATE utf8_general_ci;
As you can see action rad_id(RAD) row will be deleted if any client (strp_ID or strf_ID) will be deleted. The same goes for case(predp_id and predf_id).
Now I want to restrict delete of action rad_id(RAD row) if its included in specification. Therefore, when specification is made it inserts spec_id(SPEC) in spec-id(RAD) filed.
When specification is deleted field goes back to null and that works. BUT it allows me to delete the action rad_id(RAD) when it was included in specification(SPEC) and has that foreign key spec_id included in RAD table. And I can not let that happen. It should delete only when its null and specification key is not present.
The problem is specification will contain MULTIPLE actions rad_id's(RAD) so I can not tie it with one more column rad_id(RAD) as foreign key.
I don't know how to approach this problem.
RAD TABLE
rad_id spec_id
1 1
2 1
3 1
4 null
SPEC TABLE
spec_id rad_id-reference
1 1,2,3
As seen above SPEC table row will be made out of 3 rad_id's, I need a way to say rad_id's 1,2 and 3 can not be deleted if spec_id 1 exists. rad_id 4 can be deleted.
The problem is that I can not make rad_id-reference on SPEC table a FOREIGN KEY made out of 3 rad_id's.

I have found a way to do this.
http://sqlfiddle.com/#!9/50de2/1 If you change a delete value into 1 it will fail.
RAD TABLE
rad_id-PK
1
2
3
4
SPEC TABLE
spec_id-PK
1
2
RESTRICTDEL TABLE
res_id-PK spec_id-FK rad_id-FK
1 1 1
2 1 2
3 2 2
4 2 3
5 2 3
I have made another table that will contain both PK id's in one column, and they are FK's. one is PK and it will be unique just like spec_id From SPEC table. second is rad_id that can be double. I just have to set SET foreign_key_checks = 0; and back 1 when I'm done with inserting a new specification.
Also will need to loop with php and for every rad_id make new resdel_id entry.
This way multiple rad_id wont be deleted if there is one spec_id connecting them.

Related

Primary key or foreign key for table with identical unique columns

See indicative schema below.
Table 2 contains the different formats of films. E.g. 2D, 3D, 4D etc.
It has the formats as the columns and the end column is the film ID number from table 1.
As my film ID column in table 1 is my primary key for table 1, It lead my to believe that the film ID column in table 2 is a foreign key. However this leaves my without a primary key in table 2.
Is it best practice to leave table 2 without a primary key in this instance, or set both film IDs as primary keys for both tables, or should I create another column in table 2 allowing for a "film format ID" which would be my table 2 primary key?
For visual reference:
table 1 table 2
-------|------- -------|-------|-------|-------
Film |film ID Film ID| 3D | 4D | 2D
^primary key ^foreign key
It seems to me that many films come in multiple formats, so it would be mistake to make filmid a PK in the second table. Further the design is not normalized and highly flawed. You should have a third table of Film types that is a look up table. Then the second table should contain only the filmid and the filmtypeid and you can create a Primary key on the combination of both fields. THis is called a junction table.
Table 2 is like a child to your table 1, been the parent. This is because table 1 can exist without table 2, but table 2 cannot without table 1 because it relies on the film id primary key to create itself a set of information (you cant have a 2d or 3d formats of a non existent film).
To answer your question about making film id primary in both tables; no don't do this. The primary key uniquely identifies a column of data in a table that can be referenced with a foreign key in another table. If it was also primary key in table 2 it wouldn't refer to table 1's data because there is no relationship made.
If i understood your needs, you can use those two tables:
CREATE TABLE `film` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `film_format` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`film_id` int(11) DEFAULT NULL,
`format` enum('2D','3D','4D') CHARACTER SET latin1 DEFAULT '2D',
PRIMARY KEY (`id`),
KEY `fk` (`film_id`),
CONSTRAINT `fk` FOREIGN KEY (`film_id`) REFERENCES `film` (`id`) ON DELETE SET NULL ON UPDATE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
You are having trouble because your table design violates first normal form. Each unique combination of [film,format] should be contained in its own row in table 2.
May I suggest this alternative:
Table 1
A list of films, with a primary key of FilmID.
Table 2
A list of formats supported by films.
Columns: FilmID (FK), FormatID (FK)
Primary key: Either a compound key of FilmID+FormatID, or a surrogate key
Table 3
A list of potential film formats
Columns: FormatID, Format Description (2D, 3D, etc.)
Primary key: FormatID
You don't need a primary key on table 2, just an unique index.
But if you want, you can use an artificial key like an identity field. In this instance, at 1x1 relationship, i think thas's unnecessary.

MYSQL table for related records in another table

What is the best way to have a table to maintain related records of another table.
Example:
mytbl
-----
id sku
1 sk1
2 sk2
3 sk3
4 sk4
5 sk5
6 sk6
7 sk7
Lets say records 1, 4 and 3 are 'related'
So I want to maintain a table that tells me that they are.
relatedTbl
----------
sku related_sku
sk1 sk3
sk1 sk4
sk3 sk4
This solution would work but, is there a better solution?
EDIT: I used skus in the relatedTbl but I know I could (better) to use ids. The question is about the structure of the table more than what foreign key to use.
You have the correct solution. As you indicated, use the ID. If sku is unique, consider using it as a natural PK.
CREATE TABLE IF NOT EXISTS `mytbl` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`sku` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `relatedTbl` (
`mytbl_id` INT UNSIGNED NOT NULL,
`mytbl_id1` INT UNSIGNED NOT NULL,
PRIMARY KEY (`mytbl_id`, `mytbl_id1`),
INDEX `fk_mytbl_has_mytbl_mytbl1_idx` (`mytbl_id1` ASC),
INDEX `fk_mytbl_has_mytbl_mytbl_idx` (`mytbl_id` ASC),
CONSTRAINT `fk_mytbl_has_mytbl_mytbl`
FOREIGN KEY (`mytbl_id`)
REFERENCES `mytbl` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_mytbl_has_mytbl_mytbl1`
FOREIGN KEY (`mytbl_id1`)
REFERENCES `mytbl` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
You may want to consider adding a third field to 'mytbl' in to store a unique key for common records. for instance, field 3 would be named "uniqID", and records 1, 4 and 3 are 'related' the table would then be:
mytbl
id sku uniqID
1 sk1 1
2 sk2
3 sk3 1
4 sk4 1
5 sk5
6 sk6
7 sk7
you can then use a 'WHERE uniqID=1' clause at the end of your select statement to get the common attributes

How to DELETE a record which has foreign keys - MySQL Java

I have a table that looks like this
Car ID Car Name Part ID Stock ID
___________________________________________________
1 Audi 1 1
2 Benz 2 2
3 Corsa 1.3 3 3
4 Corsa 2.0 3 4
Now if I want to delete Corsa 1.3, it says Foreign key constraint Part ID. It can't delete it because of Part ID.
How do I fix this?
You can't delete a recrod that refers to a foreign key; that's the whole point of them.
What you would need to do is either delete the record the key refers to or remove the constraint.
You should set the field that it's complaining to null, after that, the deletion will succeed. In your case before trying to delete corsa 1.3, set it's part id to null, thus removing the reference.
Using DELETE CASCADE Option for Foreign Keys
The constraint is specified when creating the table which dictates how to deal with primary and foreign keys when updating and deleting, you can specify cascade on update and/or delete or not which is the problem your having
create table Orgs (
id bigint unsigned auto_increment,
name varchar(100) not null,
primary key (id),
unique index name_ind (name)
) engine=InnoDB;
create table Households (
id bigint unsigned,
Orgid bigint unsigned,
household varchar(20) not null,
primary key (id),
index org_ind (Orgid),
foreign key (Orgid) references Orgs(id) on update cascade on delete cascade
) engine=InnoDB;

Multiple Primary/Foreign Keys

I'm going to be honest, I'm a bit hazy on how primary and foreign keys work. I was told to setup my database by someone on here so that I had 7 tables, one for organizations, one for categories, services, and cultures, and three cross reference tables between organization on one hand, and categories, services and cultures on the other.
Take the org_culture_xref table, for instance. I have two columns, one is org_id, which is the same as the org_id column (primary key) of the organization table. The other is cult_id, which is the same as the cult_id column (primary key) of the culture table.
I believe both of the columns of the org_culture_xref table are primary and foreign keys. However, this doesn't seem to allow me to have multiple values for both of these columns. I want to be able to have several relationships between organizations and cultures - as in every organization can be associated with multiple cultures and every culture can be associated with multiple organizations.
How do I ensure that I can have multiple values for both columns?
What you're talking about is a Many-To-Many relationship. You're on the right path using a cross-reference table.
It's good to review how foreign and primary keys work; there can only be one primary key per table, but there can be multiple foreign keys. However, note that a primary key doesn't have to be limited to one column; you can have a primary key that spans two, three, or more columns.
Your solution here is to have two foreign key, one for each column/table relationship, and one primary key that spans across both tables.
Here's an example of a table I used at one time, which links cities and counties in a many-to-many relationship.
mysql> show create table xref_cities_counties\G
*************************** 1. row ***************************
Table: xref_cities_counties
Create Table: CREATE TABLE `xref_cities_counties` (
`city_id` int(10) unsigned NOT NULL,
`county_id` tinyint(3) unsigned NOT NULL,
PRIMARY KEY (`city_id`,`county_id`),
KEY `city_id` (`city_id`),
KEY `county_id` (`county_id`),
CONSTRAINT `fk_xrefcitiescounties_cityid` FOREIGN KEY (`city_id`) REFERENCES `florida_cities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_xrefcitiescounties_countyid` FOREIGN KEY (`county_id`) REFERENCES `florida_counties` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql>
mysql>
mysql> describe xref_cities_counties;
+-----------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| city_id | int(10) unsigned | NO | PRI | | |
| county_id | tinyint(3) unsigned | NO | PRI | | |
+-----------+---------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql>
I'd suggest some extra reading on the topic. It seems like you're on a good start.
The primary key for your cross ref table will be both of the columns, meaning that the combination of two ids must be unique but you can have repeats of individiual ids in either column.
Here is a statement to create such a table:
CREATE TABLE `x` (
`a_id` varchar(6) NOT NULL default '',
`b_id` varchar(6) NOT NULL default '',
PRIMARY KEY (`a_id`,`b_id`)
)
The issue itself and the cross ref table approach to many-to-many relationships applies to most (if not all) relational databases, but since I haven't used mysql in around 10 years I got that code from here, which seems to have a detailed discussion of the topic with mysql specific code.
Each column of org_culture_xref is a foreign key: org_id is a foreign key to organization, and cult_id is a foreign key to culture. The two of them together are the primary key of org_culture_xref.
So, something along these lines:
CREATE TABLE org_culture_xref
(
org_id NUMERIC(10) NOT NULL,
cult_id NUMERIC(10) NOT NULL,
PRIMARY KEY (org_id, cult_id),
FOREIGN KEY (org_id) REFERENCES organization (org_id),
FOREIGN KEY (cult_id) REFERENCES culture (cult_id)
);

Working with foreign keys - cannot insert

Doing my first tryouts with foreign keys in a mySQL database and are trying to do a insert, that fails for this reason: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails
Does this mean that foreign keys restrict INSERTS as well as DELETES and/or UPDATES on each table that is enforced with foreign keys relations?
Thanks!
Updated description:
Products
----------------------------
id | type
----------------------------
0 | 0
1 | 3
ProductsToCategories
----------------------------
productid | categoryid
----------------------------
0 | 0
1 | 1
Product table has following structure
CREATE TABLE IF NOT EXISTS `alpha`.`products` (
`id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT ,
`type` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 ,
PRIMARY KEY (`id`) ,
CONSTRAINT `funkyfunky`
FOREIGN KEY (`id` )
REFERENCES `alpha`.`ProductsToCategories` (`productid` )
ON DELETE CASCADE,
ON UPDATE CASCADE)
ENGINE = InnoDB;
Your insert is failing because the foreign key in the row you are inserting doesn't match a valid key in the constraint table. For example:
Assume you've got these two tables:
Employees
----------------------------
EmpID | Name
----------------------------
0 | John
1 | Jane
OfficeAssignments
----------------------------
OfficeID | EmpID
----------------------------
0 | 0
1 | 1
If you have a foreign key constraint on OfficeAssignments.EmpID -> Employees.EmpID, and you try to execute:
INSERT INTO OfficeAssignments (OfficeID, EmpID) VALUES (2,2)
The statement will fail because there is no entry in the Employees table with an EmpID of 2.
Constraints are designed to ensure that your dependent table always has valid data with regard to the parent table -- in this example, you will never have an office which is listed as assigned to an employee who doesn't exist in the system, either because they never existed (as in this case) or because they've been deleted (because the constraint will prevent the employee record from being deleted until the office assignment record has been deleted first).
Edit: Now that you've posted the constraint, it indeed looks like it might be set up backwards. By placing the constraint in the definition of the Products table, you are making it the child, and ProductsToCategories the parent. The constraint you've written can be read as, "a Product must be assigned to a category before it can be created". I suspect what you meant is the other way around: "a Product must be created before it can be assigned to a category." To get that result, you need to place the constraint on the ProductsToCategories table, setting the foreign key to productid and referencing Products.id.
You cannot delete a row from the parent table while there is a foreign key reference to it from a child table. Also you cannot insert/update in the child table with invalid id's in the foreign key column.
Edit: The "CONSTRAINT funkyfunky FOREIGN KEY (id)" must be declared in the "ProductsToCategories" table not in the "Products" table, because "ProductsToCategories" is referencing "Products" not the opposite as you have did.
Your products table is slightly wrong, as you don't need to reference anything from it. References go in the "other" tables, and point to the main, e.g:
create table products (
id int auto_increment,
type int,
primary key (id)
);
create table categories (
id int auto_increment,
name varchar(128),
primary key (id)
)
create table products_to_categories (
product_id int references products,
category_id int references categories
);
A foreign key enforces a valid relation between the rows in two tables. In order to be able to insert a row into a table containing a foreign key, there must be a row in the referenced table containing that key or the insert will fail. The same with delete, you can't delete the row in the referenced table while there are still rows in the table with the foreign key that still reference it. The prevents ending up with rows in the dependent table that have data, but don't have associated rows in the referenced table, i.e., a violation of referential integrity.