query with foreign key - mysql

project assignment is n to n relationship where n can be zero.
pid is primary key for the project table
eid is primary key for the employee table
a project may not be assigned to any employee.similary an employee may not have any project in his hand.
how to write this query? eid should take value as null or the value from the emp table.
pid should either take null or the value from the table project.
IS IT CORRECT.
CREATE TABLE Proj_Assign
(
eid VARCHAR(25),
pid VARCHAR(25),
PRIMARY KEY(eid,pid),
FOREIGN KEY eid REFERENCES employee(eid),
FOREIGN KEY pid REFERENCES project(pid)
);

Give this way:
FOREIGN KEY (t_eid) REFERENCES parent(eid)
ON DELETE CASCADE
Instead of using same eid twice. It is explained in the documentation.
Also, the original parent table should be there before you create this table and you need to manually insert the queries this way:
INSERT INTO `Proj_Assign` (`eid`, `pid`) VALUES (1, 1);
Whatever query you have written is right as per documentation.

Related

Create composite primary key with a name so I can reference it

At a workplace they recycle punchcard ids (for some strange reason). So it is common to have past employees clashing with current employees. As a workaround I want to have employee punchcard id, employee name+surname as the unique primary key (fingers crossed, perhaps add date-of-birth and even passport if available). That can be accomplished with
PRIMARY KEY (pid,name,surname).
The complication is that another table now wants to reference an employee by its above primary key.
Alas, said PK has no name! How can I reference it?
I tried these but no joy:
PRIMARY KEY id (pid, name, surname),
INDEX id (pid, name, surname),
PRIMARY KEY id,
INDEX id (pid, name, surname) PRIMARY KEY,
Can you advise on how to achieve this or even how to reference a composite primary key?
Update:
The table to store employees is em.
The table which references an employee is co (a comment made by an employee).
Ideally I would use pid (punchcard id) as the unique id of each employee. But since pids are recycled, this is not unique. And so I resorted to creating a composite key or an index which will be unique and can reference that as a unique employee id. Below are the 2 tables without the composite key. For brevity, I abbreviated table names and omitted surname etc. So the question is, how can I reference an employee whose id is composite from another table co.
CREATE TABLE em (
pid INT NOT NULL,
name VARCHAR(10) NOT NULL
);
CREATE TABLE co (
id INT primary key auto_increment,
em INT,
content VARCHAR(100) NOT NULL,
constraint co2em_em_fk foreign key (em) references em(pid)
);
If another table wants to reference this one by a composite key, you don't need it to have a name - just the list of fields will do. E.g.
CREATE TABLE other_table (
ID INT PRIMARY KEY AUTO_INCREMENT,
pid *defintion*,
name *defintion*,
surname *defintion*,
..., -- other fields, keys etc.
FOREIGN KEY (pid, name, surname) REFERENCES employees(pid, name, surname)
);
UPD: If you expect that the set of the fields inside PK might change and you can't make a simpler PK (auto-increment integer for example) for the original table, then your best bet might be something like this:
CREATE TABLE employee_key (
ID INT PRIMARY KEY AUTO_INCREMENT,
pid *defintion*,
name *defintion*,
surname *defintion*,
FOREIGN KEY (pid, name, surname) REFERENCES employees(pid, name, surname)
);
-- and then reference the employees from other tables by the key from employee_key:
CREATE TABLE other_table(
ID INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT NOT NULL,
... -- other fields, indexes, etc...
FOREIGN KEY (employee_id) REFERENCES employee_key(ID)
);
Then if you have a change in employee table PK, you'll only need to update employee itself and employee_key, any other tables would stay as is.
If you CAN, however, change the original employees table, I would recommend something like this:
CREATE TABLE employees(
ID INT PRIMARY KEY AUTO_INCREMENT,
pid *defintion*,
name *defintion*,
surname *defintion*,
... -- other fields, keys, etc.
UNIQUE KEY (pid, name, surname)
);
Then you'll have to maintain the logic of generating new pid's in your code, though, or have them in some side table.
UPD2: Regarding inserts and updates.
As for inserts: you need to insert these explicitly - otherwise how would you expect the relation to be established? If you're using an ORM library to communicate with your database, then it might provide you with the methods to specify linked objects without explicitly adding the IDs, but otherwise to insert a row into employees, employee_key and other_table you need to first INSERT INTO employees(...) ;, then get perform a separate INSERT for the employee_key (knowing the key fields you've just added to employees), get the auto-generated key from employee_key and then use that to perform inserts to any other tables.
You might simplify all this by writing an AFTER INSERT trigger for employees table (that would automatically create a row in employee_key) and/or performing your inserts via a stored procedure (that will even return back the key of the newly inserted row in employee_key). But still this work needs to be done, MySQL won't do it for you by default.
Updates are a bit easier, since you can specify ON UPDATE CASCADE when adding the foreign key - in that case a change to one of the fields in the employees will automatically trigger the same change in any tables that reference employees by this key.
You would define it
CONSTRAINT id
PRIMARY KEY (pid, name, surname)
But you should read more about how MySQL uses INDEXES and how to optimize them
https://dev.mysql.com/doc/refman/8.0/en/optimization-indexes.html

MySQL creating a database table query

I want to create a join table between two or more tables.
The tables are Student, and course.
Join table will be enrolled.
the business rule is that a student can only enroll in one course at a time.
I want to prevent a user from creating additional enrollments after making 1 enrollment in a course.
I am not sure what type of contraint this will be, or if its even possible.
Can anyone help?
thank you
note: I dont think it is possible to create a Primary key as the primary key of another table, ie the studentID of the student table. If i could I would. breaks the rules i think. This would be a foreign key which is not unique.
If the business rule should be ignored, and assume that a student naturally will only enroll in one course at a time.. maybe ill stop worrying...
You could create a unique index for the id_student but this provably will bring problems if a student try to register in other course later. You shoud include the id_course into the unique constraint.
ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE(studentId, course_id)
Other solution could be creating a Trigger.
The trigger should be a "before insert" trigger. This one should serch for information related to the student in the table, if the table doesn´t has information then insert information, else do nothing.
CREATE TRIGGER 'ONE_STUDENT_PER_COURSE'
BEFORE INSERT ON 'Enrollments'
FOR EACH ROW
BEGIN
DECLARE student_id INT;
SELECT n.id_student INTO student_id
FROM table_enrollments n
`IF student_id IS NULL THEN
/* I DON´T REALLY KNOW EXACTLY THE SINTAXIS FOR INSERTING DATA OF THE BEFORE INSERT FOR YOU VERSION OF MYSQL
BUT TRY THIS ONE
*/
INSERT INTO table_enrollments (student_id, course_id) SELECT student_id, course_id FROM inserted
END IF;
END; $$`
You can create unique index in join table.
CREATE UNIQUE INDEX index_name
ON your_join_table (studentId);
Each table can have a primary key. Two tables can have the same primary key defined. (But the implementation depends on the Entity Relationship Model, what we've discovered about the entities and relationships between the entities.
Based on the information provided in the question, a possible implementation of an enrollment table:
CREATE TABLE current_enrollment
( student_id INT UNSIGNED NOT NULL COMMENT 'pk, fk ref student.id'
, course_id INT UNSIGNED NOT NULL COMMENT 'pk, fk ref course.id'
, PRIMARY KEY (student_id, course_id)
, CONSTRAINT FK_currrent_enrollment_student FOREIGN KEY ( student_id )
REFERENCES student (id) ON UPDATE CASCADE ON DELETE RESTRICT
, CONSTRAINT FK_currrent_enrollment_course FOREIGN KEY ( course_id )
REFERENCES course (id) ON UPDATE CASCADE ON DELETE RESTRICT
)
The datatypes of the foreign key columns must match the datatypes of the referenced columns; in this example, i've assumed primary key columns id in both student and course, defined as datatype INT UNSIGNED
In this example, the PRIMARY KEY constraint enforces a unique constraint on the combination of (student_id,course_id). An attempt to insert a second enrollment (same student in the same course) would be a duplicate row, and that would throw a constraint violation, preventing the row from being added.
If enrollment turns out to be an entity in the model, with its own attributes, I'd opt to add a separate id column as a surrogate primary key, with a unique constraint on (student_id,course_id)
CREATE TABLE current_enrollment
( id INT UNSIGNED NOT NULL COMMENT 'pk'
, student_id INT UNSIGNED NOT NULL COMMENT 'fk ref student.id'
, course_id INT UNSIGNED NOT NULL COMMENT 'fk ref course.id'
, enrollment_dt DATETIME
, status VARCHAR(8)
, approval_by VARCHAR(8)
, PRIMARY KEY (id)
, CONSTRAINT current_enrollment_UX1 UNIQUE KEY (student_id, course_id)
, CONSTRAINT FK_currrent_enrollment_student FOREIGN KEY ( student_id )
REFERENCES student (id) ON UPDATE CASCADE ON DELETE RESTRICT
, CONSTRAINT FK_currrent_enrollment_course FOREIGN KEY ( course_id )
REFERENCES course (id) ON UPDATE CASCADE ON DELETE RESTRICT
)

What is the correct way of have foreign keys in tables that reference each other

The tables will build, but every time I try to insert values into the table I get a 1452 error of foreign key constraints fails. I wonder if the problem has to do with EMPLOYEE table has a foreign key for STORE_CODE in the STORE table, and STORE table has a foreign key for EMP_CODE in EMPLOYEE table. Is the circular reference the problem here?
ALTER TABLE EMPLOYEE DROP FOREIGN KEY STORE_CD;
ALTER TABLE STORE DROP FOREIGN KEY REGION_CD;
ALTER TABLE STORE DROP FOREIGN KEY EMPLOYEE_CD;
DROP TABLE IF EXISTS EMPLOYEE, REGION, STORE;
CREATE TABLE EMPLOYEE (
EMP_CODE int NOT NULL PRIMARY KEY,
EMP_TITLE varchar(4),
EMP_LNAME varchar(15),
EMP_FNAME varchar(15),
EMP_INITIAL varchar(1),
EMP_DOB datetime,
STORE_CODE int NOT NULL
) Engine=InnoDB;
-- Table Region
CREATE TABLE REGION (
REGION_CODE int NOT NULL PRIMARY KEY,
REGION_DESCRIPT varchar(20)
) Engine=InnoDB;
-- Table Store
CREATE TABLE STORE (
STORE_CODE int NOT NULL PRIMARY KEY,
STORE_NAME varchar(20) NOT NULL,
STORE_YTD_SALES numeric NOT NULL,
REGION_CODE int NOT NULL,
EMP_CODE int NOT NULL
) Engine=InnoDB;
ALTER TABLE EMPLOYEE ADD CONSTRAINT STORE_CD
FOREIGN KEY STORE_CD(STORE_CODE) REFERENCES STORE(STORE_CODE);
ALTER TABLE STORE ADD CONSTRAINT REGION_CD
FOREIGN KEY REGION_CD(REGION_CODE) REFERENCES REGION(REGION_CODE);
ALTER TABLE STORE ADD CONSTRAINT EMPLOYEE_CD
FOREIGN KEY EMPLOYEE_CD(EMP_CODE) REFERENCES EMPLOYEE(EMP_CODE);
It's not possible to have mutual foreign keys unless you allow at least one of the columns to be NULL. Otherwise you can never have a consistent set of tables: If you add the store first, it will refer to a nonexistent employee; if you add the employee first, it will refer to a nonexistent store.
So you need to allow the referencing column to be NULL. Then you can add a row to the first table with NULL in the referencing column, add a row to the second table, then fill in the referencing column in the first table with the ID from the second table.
In my experience with relational databases, I think you should create an
intermediate table to conect "store" with "employee" (lets name it (store_has_employee) with the atributes(idstore(fk), idemployee(fk) and isManager(boolean)).
Then you should insert the "regions" first, so you can insert a "store", then when you have registered "employees", all you have to do is conect them in "store_has_employee", and if you want to say that is the manager, just insert isManager=true.
This is the most eficient way to do it and to get faster queries.
Hope it helps.
Which one you Want to insert first? If EMPLOYEE then Make STORE_CD (nullable=true) in EMPLOYEE After that Insert STORE item with EMPLOYEE id and Update EMPLOYEE with store code.You can use Transaction for this whole process.
Due to my lack of understanding SQL, the simplest solution for me has been to remove the foreign key from the employee table so that I don't have a circular reference. Then populate the employee table first the other tables afterwards.

MySQL Foreign Key Referencing WHERE field=value

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.

MYSQL Error # 1005

I have been trying to create a foregin key with nbrseats but I i get the error 1005 all the time.
CAn someone help me!?
create table theater (
name varchar(30) primary key,
nbrseats int not null
) ENGINE=INNODB;
create table reservation (
nbr integer auto_increment,
users_username varchar(30),
cinemashow_showdate date,
movies varchar(30),
nbrseats int not null,
primary key (nbr),
foreign key (nbrseats) references theater(nbrseats),
foreign key (users_username) REFERENCES users(username)
on delete cascade,
foreign key (cinemashow_showdate, movies) references cinemashow(showdate, movie_title)
on delete cascade
) ENGINE=INNODB;
In order to be a FOREIGN KEY in another table, you must have an index created on theater.nbrseats. And in order to be able to reference a specific row reliably, it should therefore be a UNIQUE index. Otherwise, if you have duplicate values, the referencing table won't be able to discern which row it references. Even though InnoDB will allow you to create the relationship on a non-unique index, it is likely not the behavior you are looking for.
See this question for more info on that bit.
create table theater (
name varchar(30) primary key,
nbrseats int not null,
UNIQUE INDEX `idx_nbrseats` (nbrseats)
) ENGINE=INNODB;
The same will be true of the other FOREIGN KEY definitions in your table reservation, though we do not see their referenced tables posted here. The rules are:
The referenced column must be indexed (independently of any other compound indexes on it)
The referencing column must have exactly the same data type.
This kind of calls into question your design, however. If you are attaching a number of seats to a reservation, will the reservation number of seats exactly match the number available in the theater? Also this means that you could not have 2 theaters with the same number of seats.
You may need to reconsider your design here, and perhaps create a FOREIGN KEY that references theater.name instead of theater.nbrseats.