MySQL Foreign Key Referencing WHERE field=value - mysql

I have a table created in MySQL (see the code below). As you see in the code I have a foreign key manager which references the idNo. However I only want to reference to employees with the cat='B'. So I need something like
FOREIGN KEY (manager ) REFERENCES Employee(idNo WHERE cat='B').
Any ideas how I can accomplish this.
idNo SMALLINT AUTO_INCREMENT UNIQUE,
name VARCHAR(25) NOT NULL,
telNo INT(11) NOT NULL,
cat CHAR(1) NOT NULL,
manager SMALLINT,
PRIMARY KEY (idNo ),
FOREIGN KEY (manager ) REFERENCES Employee(idNo) on DELETE CASCADE)ENGINE=INNODB
AUTO_INCREMENT=1000;

Foreign keys do not allow conditions.
If you want to force the condition, you must do it via coding.
It can be done inside your non DB code (Java, PHP, VB,...), or you could create a procedure in MySQL that would be called to perform the insert and that will return an error code if condition is not matched.
If you insert from various codes/application, the procedure is the way to go since it would be centralized.

Create a new UNIQUE KEY in Employee combining idNo and cat.
ALTER TABLE Employee ADD UNIQUE KEY (idNo,cat);
Make a foreign key in the child table that references that new unique key.
ALTER TABLE SomeTable ADD FOREIGN KEY (idNo,cat) REFERENCES Employee(idNo,cat);
Then you just need to make sure cat is constrained to the single value 'B' in the child table. One solution is to create a lookup table containing just the single value 'B'.
CREATE TABLE JustB (cat char(1) PRIMARY KEY);
ALTER TABLE SomeTable ADD FOREIGN KEY(cat) REFERENCES JustB(cat);
Now the only value you can use in the child table is 'B', so naturally it can only reference rows in Employee that have a cat of 'B'.
Another solution would be to use a trigger, but I favor the lookup table.

Related

Can there be a 1 to 1 relationship for keys with multiple fields?

I am creating web-app for database management. Database can be created using diagrams ER.
Here is screen from my app:
As you can see this pseudo example shows 4x types of cases:
1) Primary key --> Primary key (1:1)
2) Unique key --> Unique key (1:1)
3) Primary key consisting of two fields --> Primary key consisting of two fields (1:1)
4) Unique key consisting of two fields --> Unique key consisting of two fields (1:1)
And here is my question:
Is it all true? I wonder about these double keys... Is this really a 1 to 1 relation?
Generally, I wonder about these first 2 cases too. Are there also true?
MySQL Workbench shows it is not true:
I dont know why but you can see MySQL Workbench shows this is one to many relation...
Oracle Sql Developer:
Can anyone tell me when 1 to 1 relationship actually is?
Documentation shows i have right:
https://docs.oracle.com/cd/E26180_01/Platform.94/RepositoryGuide/html/s1204onetoonewithauxiliarytable01.html
but diagrams ER in MySQL Workbench and Sql Developer shows something different...
SQL code from that tables:
CREATE USER "Student" IDENTIFIED BY "null";
CREATE TABLE "Student".Table1 (
PK_FK NUMBER NOT NULL
);
CREATE TABLE "Student".Table2 (
PK NUMBER NOT NULL
);
CREATE TABLE "Student".Table3 (
PK NUMBER NOT NULL,
UK_FK NUMBER
);
CREATE TABLE "Student".Table4 (
PK NUMBER NOT NULL,
UK NUMBER
);
CREATE TABLE "Student".Table5 (
PK_1_FK NUMBER NOT NULL,
PK_2_FK NUMBER NOT NULL
);
CREATE TABLE "Student".Table6 (
PK_1 NUMBER NOT NULL,
PK_2 NUMBER NOT NULL
);
CREATE TABLE "Student".Table7 (
UK_1_FK NUMBER,
UK_2_FK NUMBER
);
CREATE TABLE "Student".Table8 (
UK_1 NUMBER,
UK_2 NUMBER
);
ALTER TABLE "Student".Table1 ADD CONSTRAINT Table1_PK PRIMARY KEY (PK_FK);
ALTER TABLE "Student".Table2 ADD CONSTRAINT Table2_PK PRIMARY KEY (PK);
ALTER TABLE "Student".Table3 ADD CONSTRAINT Table3_PK PRIMARY KEY (PK);
ALTER TABLE "Student".Table4 ADD CONSTRAINT Table4_PK PRIMARY KEY (PK);
ALTER TABLE "Student".Table5 ADD CONSTRAINT Table5_PK PRIMARY KEY (PK_1_FK, PK_2_FK);
ALTER TABLE "Student".Table6 ADD CONSTRAINT Table6_PK PRIMARY KEY (PK_1, PK_2);
ALTER TABLE "Student".Table3 ADD CONSTRAINT Table3_UK1 UNIQUE (UK_FK);
ALTER TABLE "Student".Table4 ADD CONSTRAINT Table4_UK2 UNIQUE (UK);
ALTER TABLE "Student".Table7 ADD CONSTRAINT Table7_UK3 UNIQUE (UK_1_FK, UK_2_FK);
ALTER TABLE "Student".Table8 ADD CONSTRAINT Table8_UK4 UNIQUE (UK_1, UK_2);
ALTER TABLE "Student".Table1 ADD CONSTRAINT Table1_FK1 FOREIGN KEY (PK_FK)
REFERENCES "Student".Table2 (PK);
ALTER TABLE "Student".Table3 ADD CONSTRAINT Table3_FK2 FOREIGN KEY (UK_FK)
REFERENCES "Student".Table4 (UK);
ALTER TABLE "Student".Table5 ADD CONSTRAINT Table5_FK3 FOREIGN KEY (PK_1_FK, PK_2_FK)
REFERENCES "Student".Table6 (PK_1, PK_2);
ALTER TABLE "Student".Table7 ADD CONSTRAINT Table7_FK4 FOREIGN KEY (UK_1_FK, UK_2_FK)
REFERENCES "Student".Table8 (UK_1, UK_2);
That's perfectly possible. Here's an example for PostgreSQL:
create table t1 (
a int not null,
b int not null,
constraint uq1 (a, b),
constraint fk1 foreign key (a, b) references t2 (a, b)
deferrable initially deferred
);
create table t2 (
a int not null,
b int not null,
constraint uq2 (a, b),
constraint fk2 foreign key (a, b) references t1 (a, b)
deferrable initially deferred
);
In this case t1 (a,b) is unique and references t2 (a, b) that is also unique. That's a 1:1 relationship using "composite keys".
Note: This example uses "circular references" that is a standard part of SQL, but is only implemented [to my knowledge] by PostgreSQL and Oracle. It won't run in MySQL.
A one-to-one relationship is still a master-detail relationship. One table is the owner of the identifier and the other table references it through a foreign key. This is the relationship show in the MySQL Workbench and SQL Developer pictures.
Documentation shows i have right:
You link to Oracle's documentation for ATG Repository, which is a specialist tool for representing data generically, but even there we can see from the SQL that USER_TBL is the primary table and "owns" the ID column and JOB_TBL is the auxiliary table and references the ID.
CREATE TABLE usr_tbl (
id VARCHAR(32) not null,
nam_col VARCHAR(32) null,
age_col INTEGER null,
primary key(id)
);
CREATE TABLE job_tbl (
id VARCHAR(32) not null references usr_tbl(id),
function VARCHAR(32) null,
title VARCHAR(32) null,
primary key(id)
In other words, we can have a USER without a JOB but we can't have a JOB without a USER. But a USER can have only one JOB and one JOB belongs only to ONE user.
Your diagram is wrong because it renders TABLE7 and TABLE8 as peers. But foreign keys don't work like that. One table defer to the other. When I look at your notation I can't see whether TABLE8 owns TABLE7 or TABLE7 owns TABLE8. Whereas, it's quite clear in the MySQL and Oracle diagrams. The purpose of a data model is to clarify the database design not obfuscate it.
Note, it is perfectly possible to define two tables which have foreign keys that reference each other's primary key. The trick is insert data into them. This requires deferring the foreign key constraints. I view deferred constraints as a red flag, a sign of a broken data model.

Why does MySQL Workbench automatically create multiple keys when creating relationships between tables?

Check out the image below. In the movie_custom table you'll see that when I added a 1:m relationship between plist_field and movie_custom, MySQL Workbench added keys for the attached tables of plist_type and plist_view_type in additional to the key I was expecting.
Why is that?
Can/should I remove them?
Or if I should keep them, how do I auto-insert the key values from the deeper tables when doing an insert into movie_custom and I know a key of plist_field?
If we execute this schema creation:
create table parent
( pid int auto_increment primary key,
theirName varchar(100) not null
);
drop table if exists child;
create table child
( cid int auto_increment primary key,
theirName varchar(100) not null,
pid int not null,
foreign key `fk_c2p` (pid) references parent(pid)
);
Examine what happened to the child:
mysql> show create table child \G;
CREATE TABLE `child` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`theirName` varchar(100) NOT NULL,
`pid` int(11) NOT NULL,
PRIMARY KEY (`cid`),
KEY `fk_c2p` (`pid`), -- ******************** AUTO created by mysql
CONSTRAINT `child_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `parent` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
From the manual page Using FOREIGN KEY Constraints:
... index_name represents a foreign key ID. The index_name value is
ignored if there is already an explicitly defined index on the child
table that can support the foreign key. Otherwise, MySQL implicitly
creates a foreign key index that is named according to the following
rules:
If defined, the CONSTRAINT symbol value is used. Otherwise, the
FOREIGN KEY index_name value is used.
If neither a CONSTRAINT symbol or FOREIGN KEY index_name is defined,
the foreign key index name is generated using the name of the
referencing foreign key column.
So, back to your questions.
A. Why are they created? They are created because mysql creates them as specified above. They facilitate speedy reversal lookups. When a parent row is to be deleted, a fast non-table scan of children is mandated to allow or disallow the parent row removal. The auto-generated key (or one already satisfying it) is used for this purpose.
B. Should you delete them? No. Why not? Read A.
C. How do you "auto-insert the key values from the deeper tables": you acquire the id of the parent (anywhere in the hierarchy) ahead of time such as using LAST_INSERT_ID() or other program logic.

MySql: Composite Unique Key

I want to make composite key of 2 column id & code,the both columns altogether should act like Unique key for the table. while I have browsed and tried to create a table as follows,
Create table test (
`test_no` int not null AUTO_INCREMENT,
`code` varchar(5) NOT NULL,
`name` varchar(255),
`UPDBy` varchar(255),
PRIMARY KEY (`test_no`),
FOREIGN KEY (code) REFERENCES other_table(code)
// CONSTRAINT `K_test_1` Unique KEY (`test_no`,`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Just a second thought, can i make both the column as PK ? I think it will serve my purpose, RIght?
CONSTRAINT `K_test_1` Primary KEY (`test_no`,`code`) OR Primary KEY (`test_no`,`code`)
You seem to be on the wrong track somehow. Your table has an ID which is auto incremented. This is not supposed to be the primary key? Why do you call it ID then?
There are two ways to build a database: Either use the natural values a user is used to, such as an employee number a department number and so on. Or use IDs (which are usually hidden from the user). Than you would have an employee table with primary key "id" or "employee_id" or whatever, and the employee number just as a field. But as it must be unique, you would have an additional unique index on that field.
Having said that; you have a table "other_table" with primary key "code" it seems. So you are not using an ID concept here. Then why do you use it on table test? If this is a detail table on other_table, then I'd expect the composite key to be something like code + test_no (thus showing numbered tests per code) for isntance.
So the essence is: 1. Think about what your table contains. 2. Think about wether to use IDs or natural keys. The answer to these questions should help you find the correct key for your table. (And sometimes a table even doesn't have a primary key and needs none.)
You sure can make them both as PRIMARY KEY. If you don't want to, just use UNIQUE instead of UNIQUE KEY.
To set both as PRIMARY KEY, do as it follows:
...
PRIMARY KEY (`id`, `code`);
...
To set a UNIQUE CONSTRAINT, do as it follows:
...
CONSTRAINT `K_test_1` UNIQUE (`id`,`code`);
...

Specify constraints in a MySQL table

I am in the process of designing the databases for my system. There are a lot of foreign key constraints.
I was wondering whether I could get some advice, whether I should do which of the following:
1) Specify the constraints during table creation itself ie,
CREATE TABLE IF NOT EXISTS abc
(
keyword VARCHAR(20) NOT NULL,
id INT UNSIGNED NOT NULL,
FOREIGN KEY (id) REFERENCES xyz(id) ON DELETE CASCADE ON UPDATE CASCADE
)ENGINE=InnoDB;
2)create the table without FK constraints and 'alter' the table later on ie,
CREATE TABLE IF NOT EXISTS abc
(
keyword VARCHAR(20) NOT NULL,
id INT UNSIGNED NOT NULL,
)ENGINE=InnoDB;
ALTER TABLE abc ADD CONSTRAINT fk_constraint FOREIGN KEY (id) REFERENCES xyz(id)
ON DELETE CASCADE ON UPDATE CASCADE;
Table xyz is simply another table with 'id' as a primary key.
You may create the FK at once. But this is not always possible because they can refer to each other in a circular fashion. Also, you may want to add columns later, with a FK.
It may be slightly faster to add it at once, because MySQL has to validate and rebuild the table structure for some changes (although I'm not sure adding FKs is one of those). But this process will be reasonably fast on empty tables, so it doesn't matter much when you add the FK.
The result will be the same. So, there is no differences.
If I create new database, I'd create table and its foreign key in one statement. The script will look better. But in this case parent tables must be created before the child tables.
If you don't want to take into account dependencies when creating tables, you can create tables in random order in the beginning of the script and then add foreign keys using ALTER TABLE.

Adding a MySQL constraint that a field exists as primary key of the same table

I'm creating a table that has a basisId field as the primary key. There's also another field parentBasis which would be a reference to another tuple with that.basisId equal to this.parentBasis. What I want to do to is express this constraint while creating the table.
Something like: ADD CONSTRAINT CHECK EXISTS this.parentBasis AS somewhere.basisId (Obviously not real MySQL).
A quick browse through the MySQL dev pages didn't do much good. Any help would be appreciated.
Thanks.
If you're using InnoDB then you can create a foreign key from the table to itself. For example:
create table t (
id int not null primary key,
parent int null
);
alter table t add constraint foreign key (parent) references t(id);
then t.parent would either have to be NULL or a t.id value.