Many to many relational database - mysql

I have a table where player character information is kept. I have another table where all possible status affects are kept. I am trying to figure out how to create a relationship where any/all/none of the character entries in the first table can be linked to any/all/none of the status entries in the second table. My research has shown me that I will probably need a third table, and may have to use composite Primary Keys and/or surrogate keys?
So here is an update based on responses. I seem to have working what I was hoping to achieve. Here is the code:
create table characters (
char_id int primary key auto_increment,
name varchar(25)
);
create table health_status (
status_id int primary key auto_increment,
stat_name varchar(15)
);
create table char_status (
char_id int,
status_id int,
primary key (char_id, status_id)
);
insert into characters (name) values ('Godzilla');
insert into characters (name) values ('King Kong');
insert into characters (name) values ('Mecha-Dragon');
insert into characters (name) values ('Chris Hanson');
insert into characters (name) values ('Journey');
insert into characters (name) values ('Lou Diamond Phillips');
insert into characters (name) values ('RedHot');
insert into health_status (stat_name) values ('Bleeding');
insert into health_status (stat_name) values ('Shaken');
insert into health_status (stat_name) values ('Frightened');
insert into health_status (stat_name) values ('Petrified');
insert into health_status (stat_name) values ('Poisoned');
insert into health_status (stat_name) values ('Slowed');
insert into health_status (stat_name) values ('Rushed');
insert into health_status (stat_name) values ('Endowed');
insert into char_status (char_id, status_id) values (1, 1);
insert into char_status (char_id, status_id) values (1, 3);
insert into char_status (char_id, status_id) values (1, 6);
insert into char_status (char_id, status_id) values (2, 2);
insert into char_status (char_id, status_id) values (2, 4);
insert into char_status (char_id, status_id) values (3, 7);
insert into char_status (char_id, status_id) values (6, 8);
insert into char_status (char_id, status_id) values (7, 2);
insert into char_status (char_id, status_id) values (7, 7);
select characters.name, health_status.stat_name
from characters
left join char_status on characters.char_id = char_status.char_id
left join health_status ON health_status.status_id =
char_status.status_id;
I have three questions. Does anyone see any way this could be cleaned up, or a better way to achieve my goal? Also, is having the compound PK in the table char_status really doing anything useful? And finally, Is there a way to organize the output with a query to list the character name only once, followed by all its associated status - or is this something for a different language to do? Thanks for everyone's help!

Based on your structure you say you need to further create new table and put data into it.**
In order for you to connect between tableA and TableB you need to have
a Primary key in one and also its reference in other
**. Many to many relationship is something like a mutual one where tableA depends on many elements of tableB and also vice-versa.
You may have to normalize your tables first based on your situation.
Have a look at Normalization_tuorial
Next also have a look at one-many and many-many etc..

As you found in your research
create a third table with 2 fields that will hold the "id" (main field) from those 2 tables you want to make relation many to many...
CREATE TABLE `many_to_many` ( `information_id` INT(11) NOT NULL , `status_id` INT(11) NOT NULL , PRIMARY KEY (`information_id`, `status_id`)) ENGINE = MyISAM;
Pay attension to the PRIMARY KEY that depend on thos 2 fields.
Now you can add for every information_id many status_id relations,
and for status_id many information_id relations.
For first try, run this query to add values to see it
INSERT INTO `many_to_many` (`information_id`, `status_id`) VALUES (1, 1), (1, 2), (2, 1), (2, 2);

Related

What data type would I need to set for a field in a table, that restricts the values from a set of options?

I'm new to MySQL. I have a bunch of fields in my table that are standard datatypes such as varchar, INT, etc.
I do have a field that I want to have restricted to one of four options only, but I'm not sure what datatype I would need here? Or is there even a datatype for this? So if I want a field to only be able to take from a fixed set of values say "In progress", "Completed", "Not started", and "Canceled", like you could enforce via a dropdown list in Excel, how would I make that happen?
I tried searching on Google and YouTube but couldn't find anything specific to my question. I feel this is odd because even Microsoft Access has a dropdown/option datatype last I remember. So I'm obviously unaware of the basics and am looking for some help.
A simple solution would be to use the ENUM data type. For example:
create table task (
id int,
name varchar(20),
status enum ('In progress', 'Completed', 'Not started', 'Canceled')
);
insert into task (id, name, status) values (12, 'Pet Dog', 'Not started'); -- succeeds
insert into task (id, name, status) values (15, 'Pay Internet', 'Pending'); -- fails
EDIT:
However, the solution above forces the status to be static. If later on you needed toadd an extra status you would need to modify the table structure. Not great.
If you wanted to have dynamic status all the while they are fully validated, you can use a foreign key. For example:
create table task_status (
id int primary key not null,
name varchar(50),
unique (name)
);
insert into task_status (id, name) values
(1, 'In progress'),
(2, 'Completed'),
(3, 'Not started'),
(4, 'Canceled');
create table task (
id int,
name varchar(20),
status int not null,
constraint fk1 foreign key (status) references task_status (id)
);
insert into task (id, name, status) values (12, 'Pet Dog', 3); -- succeeds
insert into task (id, name, status) values (15, 'Pay Internet', null); -- fails
insert into task (id, name, status) values (15, 'Buy Cat', 5); -- fails
But if I add the new status "Pending":
insert into task_status (id, name) values (5, 'Pending');
insert into task (id, name, status) values (15, 'Buy Cat', 5); -- succeeds!

Unique constraints across a many to many relationship table

Is there any way to add a constraint to ensure that an entry of X in one column can then only allow an entry of Y in another column?
Say I have two tables, stripped down to minimal columns, tbl_1 has a pk. tbl_2 has 2 columns - a pk and a text string.
These tables are joined by a 3rd relationship table because they're many to many and it uses pk from tbl1 and tbl2.
t1_pk t2_pk | t2_str t1fk | t2fk
x 1 AAA x 1
y 2 BBB x 2
z 3 AAA y 3
4 BBB y 4
z 1
z 2
All entries above are allowed, but now I'm trying to figure out how I can constrict the relationship table so that the string attached to t2_pk can only tie in to the t1_pk ONCE. E.g. in the 3rd table:
t1fk | t2fk
x 3
would not be allowed because x-1 exists and both 1 and 3 have the string AAA attached. One way I can think without making 3 more tables and going round in circles, is to move the string to the relationship table and add a constraint so if the t2fk number exists in the table already it'll only allow the number again if accompanied by the same string.
is there a background process for this I can declare like adding a unique constraint, or would it simply need to be imposed by a stored procedure?
Either you add a t2_str column to your third table that contains the relations or you create a new table for this purpose. Here an example how to implement the new table tab_constr.
drop table if exists tab_constr;
drop table if exists tab_rel;
drop table if exists tab_1;
drop table if exists tab_2;
CREATE TABLE tab_1 (
t1_pk varchar(5),
PRIMARY KEY (t1_pk)
);
CREATE TABLE tab_2 (
t2_pk INT,
t2_str varchar(10) NOT NULL,
PRIMARY KEY (t2_pk),
INDEX(t2_pk, t2_str)
);
CREATE TABLE tab_rel (
t1_pk varchar(5),
t2_pk INT,
PRIMARY KEY (t1_pk,t2_pk),
INDEX (t2_pk),
FOREIGN KEY (t1_pk) REFERENCES tab_1(t1_pk),
FOREIGN KEY (t2_pk) REFERENCES tab_2(t2_pk)
);
CREATE TABLE tab_constr (
t1_pk varchar(5),
t2_str varchar(10),
t2_pk int,
PRIMARY KEY pair_already_exists(t1_pk,t2_str),
INDEX(t1_pk, t2_pk),
INDEX(t2_pk, t2_str),
FOREIGN KEY (t1_pk, t2_pk) REFERENCES tab_rel(t1_pk, t2_pk)
ON DELETE CASCADE,
FOREIGN KEY (t2_pk, t2_str) REFERENCES tab_2(t2_pk, t2_str)
ON UPDATE CASCADE
);
CREATE TRIGGER tr_ins_rel AFTER INSERT ON tab_rel
FOR EACH ROW
BEGIN
INSERT INTO tab_constr ( t1_pk, t2_str, t2_pk)
select new.t1_pk, t2_str, new.t2_pk
from tab_2
where t2_pk=new.t2_pk
;
END;
INSERT INTO tab_1 (t1_pk) VALUES ('x');
INSERT INTO tab_1 (t1_pk) VALUES ('y');
INSERT INTO tab_1 (t1_pk) VALUES ('z');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (1, 'AAA');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (2, 'BBB');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (3, 'AAA');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (4, 'BBB');
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 1);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 2);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('y', 3);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('y', 4);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('z', 1);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('z', 2);
commit;
The following statement will raise an error:
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 3);
This also raises an error
UPDATE tab_2 set t2_str='BBB' where t2_pk=1;
But this will work
DELETE FROM tab_rel where t1_pk='x' and t2_pk=1;
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 3);
and this will work
UPDATE tab_2 set t2_str='XXX' where t2_pk=1;
Here you can try it out.
Of course this additional table violates normal form and adds redundancy to your database. But that is no problem because this table tab_constr is an auxiliary structure like an index and it will be automatically maintained by the database. So no insert/update/delete anomalies will occur.

Adding items in MySQL table

I was preparing to create a website using PHPMyAdmin and I bang into a problem : I don't understant why my code does things I don't want.
This is the code to create the tables and some random entries :
create table stud (
matrnr int primary key,
pname Varchar(30) not null
);
create table prof (
persnr int primary key,
pname Varchar(50) not null
);
create table vorl (
vorlnr int primary key,
titel varchar(50),
prof int references prof(persnr) on delete set null
);
create table prüfen (
stud int references stud(matrnr) on delete cascade,
vorl int references vorl(vorlnr),
prof int references prof(persnr) on delete set null,
note float,
primary key(Stud, vorl)
);
insert into stud values
(1, 'G'),
(2, 'F'),
(3, 'C');
insert into Prof values
(1, 'M'),
(2, 'L'),
(3, 'M');
insert into vorl values
(1, 'Info1', 'M'),
(1, 'Info2', 'L'),
(1, 'Info3', 'M');
insert into prüfen values
(1, 1, 1, 2.0),
(1, 2, 1, 1.7),
(2, 3, 2, 2.3);
At this position I tried
Insert into prüfen values (3, 1, 4, 2.0);
but the was still only 3 lines in the table prüfen.
Any help is wellcome.
Have a good week.
Your final insert failed because it references a professor with a prof ID of 4, which does not exist in the prof table.
If you look closely at your definition for the prüfen table, this will be more clear:
create table prüfen (
stud int references stud(matrnr) on delete cascade,
vorl int references vorl(vorlnr),
prof int references prof(persnr) on delete set null,
note float,
primary key(Stud, vorl)
);
The field prof is a foreign key into the prof table. MySQL will require that this field references a professor which actually exists. It does not in the case of your final insert. To get around this error, you could create such a professor, e.g.
insert into Prof values
(4, 'M');
You didn't report an error in your question, which seems off to me. Maybe you failed to mention it, or perhaps your error reporting is turned off for some reason.

mysql statement wont insert

Hey guys I've searched for answers through the forums but to no avail so I'm using MySql and I'm trying to insert statements for certain tables and they aren't going into the tables and I'm getting errors like "Msg 8152, Level 16, State 14, Line 1
String or binary data would be truncated. The statement has been terminated."
These are the statements I'm having problems with.`INSERT INTO Course VALUES
INSERT INTO Course VALUES (12345, 'DatabaseManagement', '2015-2-1', '2014-5-9');
INSERT INTO Course VALUES (12346, 'Calculus', '2015-1-12', '2015-5-9');
INSERT INTO Course VALUES (12347, 'Biology', '2015-1-3', '2015-5-9');
INSERT INTO Course VALUES (12348, 'Chemistry', '2015-1-2', '2015-5-9');
INSERT INTO Grade VALUES (10, 12345, 012, 'A');
INSERT INTO Grade VALUES (11, 12346, 013, 'B');
INSERT INTO Grade VALUES (12, 12347, 014, 'C');
INSERT INTO Grade VALUES (13, 12348, 015, 'D');
INSERT INTO Grade VALUES (14, 12345, 016, 'B');
INSERT INTO Student VALUES (54321, 'Rachel', 'Cotterel', '2013-4-15', '2016-3-4');
INSERT INTO Student VALUES (54320, 'John', 'Smith', '2012-1-23', NULL);
INSERT INTO Student VALUES (54319, 'Johny', 'Depp', '2010-5-12', '2012-10-10');
INSERT INTO Student VALUES (54318, 'Orlando', 'Bloom', '2014-6-24', NULL);
INSERT INTO Student VALUES (54317, 'Linda', 'Jacob', '2015-4-4', '2019-8-6');
I didn't get any error for insert into Course statements. I got error for INSERT INTO Grade statements. Its because there is no reference available for StudentID 012,013 etc in Student table. And you are trying to add them in grade table.
Try using this:
INSERT INTO table1 (column1,column2,column3,...)
VALUES (value1,value2,value3,...);
These are the field types:
CREATE TABLE Course
(
CourseID int,
Description varchar(20) NOT NULL,
StartDate DATE NOT NULL,
EndDate DATE NOT NULL,
CONSTRAINT [PK_CourseID] PRIMARY KEY (CourseID)
);
CREATE TABLE Grade
(
GradeID integer(10) NOT NULL,
CourseID integer(10) NOT NULL,
StudentID integer(10) NOT NULL,
Grade varchar (10) NULL,
CONSTRAINT [PK_GradeID] PRIMARY KEY (GradeID),
CONSTRAINT [FK_CourseID] FOREIGN KEY (CourseID) REFERENCES Course(CourseID),
CONSTRAINT [FK_StudentID] FOREIGN KEY (StudentID) REFERENCES Student(StudentID)
);
CREATE TABLE Student
(
StudentID integer(10) NOT NULL,
FirstName varchar(45) NOT NULL,
LastName varchar(45) NOT NULL,
RegistrationDate varchar (45) NOT NULL,
GraduationDate DATE NULL,
CONSTRAINT [PK_StudentlID] PRIMARY KEY (StudentID)
);
String or binary data would be truncated
The reason that you get this message should be that you are trying to insert some value to some field to which you haven't assigned enough size to hold the value.
Can you send what the exact error message you get?
I tried to do it myself.But the error I got was from you insertion query to Grade table foreign key fails which refer Student table because you are trying to insert Student_IDs which are not there in you Student table

Mysql insert array from another table and fill the rest with default values

here's my question:
I have a table TRUST(id INT, trustlevel INT) which contains records (1, 5) and (2, 3). I also have an array containing ids (1, 2, 3, 4, 5).
What I want to achieve is to insert all the ids from the array into a temporary table called PRESELECTED(id INT, trustlevel INT DEFAULT 10) in such a way that the ids with trustlevels which are in TRUST to be copied and the rest of the array to accept the default value which is 10 in this case. So at the end PRESELECTED will have records (1, 5), (2, 3), (3, 10), (4, 10), (5, 10).
I have figured out how to put the values from the TRUST table but I am stuck with the rest:
CREATE TEMPORARY TABLE PRESELECTED (id INT, trustlevel INT DEFAULT 10);
INSERT INTO PRESELECTED (
SELECT * FROM TRUST WHERE id IN (1, 2, 3, 4, 5)
)
The problem with this is that it only inserts 1 and 2 because 3, 4 and 5 are not in TRUST
Any quick suggestions?
Add unique key on ID ( PK or UNIQUE KEY )
Insert the existing ids from TRUST first
INSERT INTO PRESELECTED SELECT id,trustlevel FROM TRUST WHERE id IN(1,2,3,4,5);
Fill the missing ids
INSERT IGNORE INTO PRESELECTED (id) VALUES (1),(2),(3),(4),(5);