MySql replace with multiple primary keys - mysql

I have a table which has three primary keys and references three other tables
Here is the table scheema:
CREATE TABLE IF NOT EXISTS training_matrix_reference(
employee INT NOT NULL,
training_matrix INT NOT NULL,
training_record INT UNSIGNED NOT NULL,
PRIMARY KEY (employee, training_matrix,training_record),
FOREIGN KEY (employee) REFERENCES employees(id),
FOREIGN KEY (training_matrix) REFERENCES training_matrix_courses(id),
FOREIGN KEY (training_record) REFERENCES training_records(m_id)
)
I'm trying to craft a REPLACE statement which updates the training_record column or training_matrix column or both columns or creates a new row if not exists, but I also need to check that the employee belongs to the same company.
Here's what I tried so far:
REPLACE INTO `training_matrix_reference`
( employee, training_matrix, training_record ) (
SELECT id, '5', '100'
FROM employees
WHERE id =22
AND company =64
)
So my theory was that this should have replaced the first row in the table, updating training_record to 100 but in fact it actually created a new row:
22 | 5 | 100
My guess is that this happened because training_record is a primary key?
But I'm not sure that removing the primary keys/references is the right way to go as this table is used as a many to many table in other queries.
Effectively what I'm trying to do is:
REPLACE INTO `training_matrix_reference`
( employee, training_matrix, training_record )
VALUES
(22,33,18)
WHERE
employee = 22
and training_matrix = 5
and training_record = 2189
But obviously a replace statement doesn't have a where clause.
I did check out these similar questions:
MySQL REPLACE INTO on multiple keys?
mysql REPLACE query with multiple primary keys
But unfortunately MySql is not my strong suit and I could really use some help.
I hope I explained things clearly, Thanks

The PRIMARY KEY of the training_matrix_reference table is the combination of three columns. The table doesn't have multiple primary keys, it has a single PRIMARY KEY.
The REPLACE syntax you have is equivalent to performing:
DELETE FROM training_matrix_reference
WHERE employee = 22
AND training_matrix = 5
AND training_record = 100
;
INSERT INTO training_matrix_reference (employee, training_matrix, training_record)
VALUES (22, 5, 100);
;
The DELETE action only removes rows where the entire primary key is matched. Given the information you provided, we'd expect a row to be added to the table.
Did you have a question?

you should make a joining table between (employee, training_matrix_reference)
or dispense at lest one relation

Related

How to create an n-n relation on the same table with composite primary key in MySQL

I want to store if two events are combinables.
It's a n to n relation, so I need to have a pivot table with these constraints :
PK(event_1, event_2) = PK(event_2, event_1)
event_1 is a reference to id in table events
event_2 is a reference to id in table events
I tried to create my table with this query :
event_id_1 INT UNSIGNED,
event_id_2 INT UNSIGNED,
cumulative_place INT,
PRIMARY KEY(event_id_1,event_id_2),
FOREIGN KEY(event_id_1)
REFERENCES events(id)
ON DELETE CASCADE,
FOREIGN KEY(event_id_2)
REFERENCES events(id)
ON DELETE CASCADE
);
Following MySQL Documentation
I have some questions about that :
Is it optimized for search query, for example if i want all events that are combinables with event1 whatever if event1 is in the first column or second ?
Do I need to manually manage primary key for INSERT and UPDATE or MySQL do the job ? for example can I just insert cumulative place number for (event1, event2) primary key and if row is store as (event2, event1) this works as well.
Sort the pair.
INSERT ...
VALUES (
LEAST("e1", "e2"),
GREATEST("e1", "e2"),
...)
Similarly, sort the pair when doing a lookup. That way you have 1 row, not 2, and you don't have to look for both orders.

Update of primary key would cause duplicate entries in foreign table

I have two tables described by the following SQL Fiddle. My application needs to insert new records in tblA in between two already existing records. For example, if tblA has 6 records with AID ranging from 0 to 5 and I want to insert a new record with AID being 4, I increment the AID of tuple 4 and tuple 5 by one and then insert the new record. Thus, I use the following prepared statement to increment the value of the column AID of the tuples of both tblA and tblB (via cascading) by one:
update tblA set AID = (AID + 1) where AID >= ? order by AID desc;
On my test Installation the above Statement works great. However, on our production system we get the following error message in some, but not all cases:
Foreign key constraint for table 'tblA', record '4' would lead to a duplicate entry in table 'tblB'
Now, it is unclear to me what exactly causes the problem and how to solve the issue.
I appreciate any tips. Thanks in advance!
About tblB
This
create table if not exists tblB(
BID integer not null,
AID integer not null,
constraint fkB_A foreign key(AID) references tblA(AID),
primary key(AID, BID)
);
should probably be
create table if not exists tblB(
BID integer not null,
AID integer not null,
constraint fkB_A foreign key(AID) references tblA(AID)
on update cascade,
-- ^^^^^^^^^^^^^^^^
primary key(AID, BID)
);
Surrogate ID numbers in the relational model of data and in SQL databases are meaningless. Unless you know more than you've included in your question, AID and BID are meaningless. In a properly designed database, there's never a need to insert a row between two other rows based solely on their surrogate ID numbers.
If your real-world requirement is simply to insert a timestamp between "2015-12-01 23:07:00" and "2015-12-04 14:58:00", you don't need the ID number 4 to do that.
-- Use single quotes around timestamps.
insert into tblA values (-42, '2015-12-03 00:00:00');
select * from tblA order by RecordDate;
AID RecordDate
--
0 2015-11-07 16:55:00
1 2015-11-08 22:16:00
2 2015-11-10 14:26:00
3 2015-12-01 23:07:00
-42 2015-12-03 00:00:00
5 2015-12-04 14:58:00
6 2015-12-13 10:07:00
About tblA
This
create table if not exists tblA(
AID integer not null,
RecordDate varchar(25),
constraint pkA primary key(AID)
);
should probably be
create table if not exists tblA(
AID integer not null,
RecordDate varchar(25) not null,
-- ^^^^^^^^
constraint pkA primary key(AID)
);
Without that not null, you can insert data like this.
AID RecordDate
--
17 Null
18 Null
19 Null
Since surrogate ID numbers are meaningless, these rows are all essentially both identical and identically useless.
About the update statement
update tblA
set AID = (AID + 1)
where AID >= 4
order by AID desc;
Standard SQL doesn't permit order by in this position in update statement. MySQL documents this as
If the ORDER BY clause is specified, the rows are updated in the order
that is specified.
The relational model and SQL are set-oriented. Updates are supposed to happen "all at once". IMHO, you'd be better off learning standard SQL and using a dbms that better supports standard SQL. (PostgreSQL springs to mind.) But adding on update cascade to tblB (above) will let your update statement succeed in MySQL.
update tblA
set AID = (AID + 1)
where AID >= 4 order by AID desc;
adding on update cascade might solve your problem
create table if not exists tblB(
BID integer not null,
AID integer not null,
constraint fkB_A foreign key(AID)
references tblA(AID)
on update cascade,
primary key(AID, BID));

Can we refer to two different tables for one foreign key?

I have these tables:
table1
-----------------------
tb1_id
name
other stuff
table2
-------------------------------
tb2_Id
other stuff
table 3
--------------------------------
id
ref Id ->either tb2_id or tb1_id
Can this be achieved from the below code ?
CREATE TABLE `eloan`.`table3` (
`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`refId` VARCHAR(45) NOT NULL DEFAULT '',
PRIMARY KEY(`id`),
CONSTRAINT `refId` FOREIGN KEY `refId` (`refId`, `refId`)
REFERENCES `table2` (`tb2_id`, `tb1_id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT
)
ENGINE = InnoDB;
This code returned a "duplicate redid" error.
No. That's not possible.
If you want to use just a single refId column, as you show, you will not be able to declare/define foreign key constraint(s) to reference more than one table.
You may be able to define BEFORE INSERT, BEFORE UPDATE and BEFORE DELETE triggers on the three tables, to perform some checks of integrity, and have the trigger throw an exception/error to prevent some changes.
Obviously, you could define two separate columns in table3, one can be a foreign key reference to table1 the other can reference table2. You can define foreign key constraints.
You can allow both of the columns to be NULL.
If you want to enforce only one or the other column to be populated (at least one of the columns has to be NULL and the other column has to be NOT NULL), you can enforce that in BEFORE INSERT and BEFORE UPDATE triggers.

Best MySQL Table Structure: 2 Parents, 1 Child

I have two parent tables, BusinessGroup and SocialGroup, and one child table, Members. A Member can belong to either parent, but not both.
As far as I can see, there are two options for constructing the child table.
Opt 1: Include a field for ParentType, and another for ParentID. The ParentType would be an enum (Business, Social) and the ParentID would be the PK from the respective parent table.
Opt 2: Include a field for BusinessGroupID, and another for SocialGroupID. In this case, the fields would need to be nullable, and only one could contain a value.
Any ideas on which approach is best?
I tried option 1 in MySQL, and created two foreign keys from the child back to the parents. I ran into trouble when inserting values though, since MySQL was expecting a corresponding value in BOTH parent tables.
As a supplementary question: how do things change if I have a larger number of parents, e.g. 6?
Thanks!
CREATE TABLE Group (
GroupID integer NOT NULL
, Name varchar(18)
, Description varchar(18)
, GroupType varchar(4) NOT NULL
-- all columns common to any group type
);
ALTER TABLE Group ADD CONSTRAINT pk_Group PRIMARY KEY (GroupID) ;
CREATE TABLE BusinessGroup (
GroupID integer NOT NULL
-- all columns specific to business groups
);
ALTER TABLE BusinessGroup
ADD CONSTRAINT pk_BusinessGroup PRIMARY KEY (GroupID)
, ADD CONSTRAINT fk1_BusinessGroup FOREIGN KEY (GroupID) REFERENCES Group(GroupID) ;
CREATE TABLE SocialGroup (
GroupID integer NOT NULL
-- all columns specific to social groups
);
ALTER TABLE SocialGroup
ADD CONSTRAINT pk_SocialGroup PRIMARY KEY (GroupID)
, ADD CONSTRAINT fk1_SocialGroup FOREIGN KEY (GroupID) REFERENCES Group(GroupID) ;
CREATE TABLE Person (
PersonID integer NOT NULL
, GroupID integer NOT NULL
);
ALTER TABLE Person
ADD CONSTRAINT pk_Person PRIMARY KEY (PersonID)
, ADD CONSTRAINT fk1_Person FOREIGN KEY (GroupID) REFERENCES Group(GroupID) ;
"parent tables" is probably a misnomer - in the relational model I'd flip your relationship. e.g. make members the master records table, and a join table that allows 1-1 mapping, so have a PK of member_id or whatever the right field is, and map to the FK in either BusinessGroup or SocialGroup.

Is it possible to have a mysql table accept a null value for a primary_key column referencing a different table?

I have a table that has a column which holds the id of a row in another table. However, when table A is being populated, table B may or may not have a row ready for table A.
My question is, is it possible to have mysql prevent an invalid value from being entered but be ok with a NULL? or does a foreign key necessitate a valid related value?
So... what I'm looking for (in pseudo code) is this:
Table "person" id | name
Table "people" id | group_name | person_id (foreign key id from table person)
insert into person (1, 'joe');
insert into people (1, 'foo', 1)//kosher
insert into people (1, 'foo', NULL)//also kosher
insert into people(1, 'foo', 7)// should fail since there is no id 7 in the person table.
The reason I need this is that I'm having a chicken and egg issue where it makes perfect sense for the rows in the people table to be created before hand (in this example, I'm creating the groups and would like them to pre-exist the people who join them). And I realize that THIS example is silly and I would just put the group id in the person table rather than vice-versa, but in my real-world problem that is not workable.
Just curious if I need to allow any and all values in order to make this work, or if there's some way to allow for null.
If you set the column as nullable then it can contain NULL even if it is a foreign key referencing a column in another table.
Foreign keys can be null.
When the row in the referenced table is entered you'll have to UPDATE that row to point to it.
You set a foreign key column to accept nulls by setting the optionality of the column to NULL:
DROP TABLE IF EXISTS `example`.`tableb`;
CREATE TABLE `example`.`tableb` (
`id` int(10) unsigned NOT NULL auto_increment,
`person_id` int(10) unsigned default NULL, -- notice, !say "NOT NULL" like id
PRIMARY KEY (`id`),
CONSTRAINT `FK_tableb_1` FOREIGN KEY (`person_id`) REFERENCES `tablea` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
That said, tablea has to have at least one record in it before you attempt to insert a null value into the tableb reference column. Otherwise, MySQL will throw an error (for me anyways, on 4.1).