can 2 entities have 2 relationships - mysql

In database design, can 2 entities have 2 relationships among themselves? i.e for example there are 2 entities donor and admin.. there are 2 relationships
1. admin accesses donor details
2. admin can contact donor and vice versa
can we join them with 2 relationships?

Definitely, although how much sense it makes to model "accesses" and "contacts" relations in a database depends on your application. I'll stay with your example though and assume these relations are n to n. Here is how the SQL could look like (warning, syntax not tested):
CREATE TABLE admin (
id int unsigned AUTO_INCREMENT PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE donor (
id int unsigned AUTO_INCREMENT PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE admin_donor_access_details (
id_admin int unsigned NOT NULL,
id_donor int unsigned NOT NULL,
PRIMARY KEY (id_admin, id_donor),
CONSTRAINT FOREIGN KEY(id_admin) REFERENCES admin(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FOREIGN KEY(id_donor) REFERENCES donor(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE admin_donor_contact (
id_admin int unsigned NOT NULL,
id_donor int unsigned NOT NULL,
PRIMARY KEY (id_admin, id_donor),
CONSTRAINT FOREIGN KEY(id_admin) REFERENCES admin(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FOREIGN KEY(id_donor) REFERENCES donor(id) ON DELETE CASCADE ON UPDATE CASCADE
);
The two relations could also be expressed in a single join table with boolean flags, like this:
CREATE TABLE admin_donor (
id_admin int unsigned NOT NULL,
id_donor int unsigned NOT NULL,
detail_access tinyint(1) NOT NULL,
contact tinyint(1) NOT NULL,
PRIMARY KEY (id_admin, id_donor),
CONSTRAINT FOREIGN KEY(id_admin) REFERENCES admin(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FOREIGN KEY(id_donor) REFERENCES donor(id) ON DELETE CASCADE ON UPDATE CASCADE
);
This will put some extra effort on your code because you need to determine whether to insert or update a row when adding a relationship, and whether to delete or update a row when removing a relationship, but in my opinion this is still a usable alternative.

Related

MySQL - Many-To-Many Relationship between three entities

I am having trouble figuring out the best design for my many-to-many relationship in my database. My project allows users to create what we are calling log alarms. A log alarm will check if a given log meets certain criteria and, if so, it will send a message to an AWS SNS topic. What I want to do is relate log alarms to AWS SNS topics. I also want to relate which user assigned that log alarm to that AWS SNS topic.
I have a table class XRefUserLogAlarmSNSTopic. It has three foreign keys. The goal of this table is to relate which SNS topics are related to what log alarms and to indicate which user made the relation. This seems rather messy to me and I get all sorts of errors when I try to create new log alarms or join tables in Spring JPA. My question is, is there are better database structure for what I am trying to achieve
UserId INT NOT NULL AUTO_INCREMENT,
Username VARCHAR(50) NOT NULL,
Password TEXT NOT NULL,
Email VARCHAR(255) NOT NULL,
Dashboard LONGTEXT NOT NULL,
PRIMARY KEY (UserId),
UNIQUE (Username),
UNIQUE (Email)
);
CREATE TABLE SNSTopics (
SNSTopicId INT NOT NULL AUTO_INCREMENT,
TopicName VARCHAR(50) NOT NULL,
TopicArn VARCHAR(255) NOT NULL,
PRIMARY KEY (SNSTopicId),
UNIQUE (TopicName),
UNIQUE (TopicArn)
);
CREATE TABLE LogGroups (
LogGroupId INT NOT NULL AUTO_INCREMENT,
Name VARCHAR(255) NOT NULL,
PRIMARY KEY (LogGroupId),
UNIQUE (Name)
);
CREATE TABLE Keywords (
KeywordId INT NOT NULL AUTO_INCREMENT,
Word VARCHAR(70),
PRIMARY KEY (KeywordId),
UNIQUE (Word)
);
CREATE TABLE LogAlarms (
LogAlarmId INT NOT NULL AUTO_INCREMENT,
LogLevel VARCHAR(5) NOT NULL CHECK (LogLevel IN ('TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR')),
Comparison VARCHAR(2) CHECK (Comparison IN ('==', '<', '<=', '>', '>=')),
AlarmName VARCHAR(255) NOT NULL,
KeywordRelationship CHAR(3) CHECK (KeywordRelationship IN ('ANY', 'ALL', NULL)),
PRIMARY KEY (LogAlarmId),
UNIQUE (AlarmName)
);
CREATE TABLE MetricAlarms (
MetricAlarmId INT NOT NULL AUTO_INCREMENT,
AlarmArn VARCHAR(100) NOT NULL,
PRIMARY KEY (MetricAlarmId),
UNIQUE (AlarmArn)
);
CREATE TABLE XRefUserMetricAlarm (
UserMetricAlarmId INT NOT NULL AUTO_INCREMENT,
UserId INT NOT NULL,
MetricAlarmId INT NOT NULL,
PRIMARY KEY (UserMetricAlarmId),
FOREIGN KEY (UserId) REFERENCES Users(UserId) ON DELETE CASCADE,
FOREIGN KEY (MetricAlarmId) REFERENCES MetricAlarms(MetricAlarmId) ON DELETE CASCADE,
UNIQUE (UserId, MetricAlarmId)
);
CREATE TABLE XRefLogAlarmLogGroup (
LogAlarmLogGroupId INT NOT NULL AUTO_INCREMENT,
LogAlarmId INT NOT NULL,
LogGroupId INT NOT NULL,
PRIMARY KEY (LogAlarmLogGroupId),
FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
FOREIGN KEY (LogGroupId) REFERENCES LogGroups(LogGroupId) ON DELETE CASCADE,
UNIQUE (LogAlarmId, LogGroupId)
);
CREATE TABLE XRefLogAlarmKeyword (
LogAlarmKeywordId INT NOT NULL AUTO_INCREMENT,
LogAlarmId INT NOT NULL,
KeywordId INT NOT NULL,
PRIMARY KEY (LogAlarmKeywordId),
FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
FOREIGN KEY (KeywordId) REFERENCES Keywords(KeywordId) ON DELETE CASCADE,
UNIQUE (LogAlarmId, KeywordId)
);
CREATE TABLE XRefUserLogAlarmSNSTopic (
UserLogAlarmSNSTopicId INT NOT NULL AUTO_INCREMENT,
LogAlarmId INT NOT NULL,
SNSTopicId INT NOT NULL,
UserId INT NOT NULL,
PRIMARY KEY (UserLogAlarmSNSTopicId),
FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
FOREIGN KEY (SNSTopicId) REFERENCES SNSTopics(SNSTopicId) ON DELETE CASCADE,
FOREIGN KEY (UserId) REFERENCES Users(UserId) ON DELETE CASCADE,
UNIQUE (LogAlarmId, SNSTopicId, UserId)
);```
To match your description, your XRefUserLogAlarmSNSTopic is not correct.
You do not actually want to link three entities, just two: you want to relate log alarms to AWS SNS topics (which are the two values that identify that relationship), and then add a user as an attribute to that relation. Although in this case this specific attribute refers to another entity, it is logically not fundamentally different than e.g. a timestamp that stores when that relationsship was created (by that user).
The difference to your current table is the primary key/unique key: your current table allows you to add a relationship between an alarm and a topic several times if different users add them, as only (alarm, topic, user) needs to be unique, instead of (alarm, topic) being unique, and user being an attribute to that relation.
I would also consider if you want an ON DELETE CASCADE for the UserId column. While cascading for LogAlarmId and SNSTopicId makes sense, it's not obvious that you need to remove all relations when you delete the user that created them (although it of course depends on your requirements). It may be better to just set them to null. So I would propose a table like
CREATE TABLE XRefLogAlarmSNSTopic ( -- user not part of table name
LogAlarmSNSTopicId INT NOT NULL AUTO_INCREMENT,
LogAlarmId INT NOT NULL,
SNSTopicId INT NOT NULL,
UserId INT NULL, -- null
PRIMARY KEY (UserLogAlarmSNSTopicId),
FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
FOREIGN KEY (SNSTopicId) REFERENCES SNSTopics(SNSTopicId) ON DELETE CASCADE,
FOREIGN KEY (UserId) REFERENCES Users(UserId) ON DELETE SET NULL, -- set null
UNIQUE (LogAlarmId, SNSTopicId) -- user not part of primary key candidate
)
It is obviously also possible that you want that 3-way-relationship, e.g. each user creates their own alarm-topic-relations, in which case your table would be correct, just your description would not be precise enough.

Deleting tables on a relational database (InnoDB)

I managed a relational database and I want to delete a table and their sons (reference as a reference value like fk_table_value).
When I'm doing a simple "DELETE FROM companies WHERE id=4" I have that error message : "Cannot delete or update a parent row: a foreign key constraint fails".
Here you can see my database map.
CREATE TABLE buildings (
building_no INT PRIMARY KEY AUTO_INCREMENT,
building_name VARCHAR(255) NOT NULL,
address VARCHAR(255) NOT NULL
);
CREATE TABLE rooms (
room_no INT PRIMARY KEY AUTO_INCREMENT,
room_name VARCHAR(255) NOT NULL,
building_no INT NOT NULL,
FOREIGN KEY (building_no)
REFERENCES buildings (building_no)
ON DELETE CASCADE
);
Lets say you have defined two tables like this. So we can see that rooms have a foreign key on buildings and it is set ON DELETE CASCADE. That means that if entity from buildings is deleted all the room with that building_no will be also deleted.
This will also fix your problem.

How to update FK linked to multiple table - Cascade on Update

I have 3 tables which are linked to each other
task
client
compliance
The relationship is as shown in diagram below
The compliance table has the foreign key as below
The task table has the foreign key as below
Issue:
When I edit/update clientno in client table, I get
1452: Cannot add or update a child row: a foreign key constraint fails
(`task`, CONSTRAINT `task_ibfk_1` FOREIGN KEY (`officeid`, `clientid`) REFERENCES `client` (`officeid`, `clientno`) ON UPDATE CASCADE)
I expected that when clientno was changed in client table, the same will be updated in both complaince and task table.
I guess I am hitting a known limitation of InnoDB engine. Which goes not allow cascading updates to FK. If this is true, then what is the solution to updating the 3 tables with new clientno?
EDIT 1: As pointed out by #pankaj, how to overcome
If ON UPDATE CASCADE recurses to update the same table it has previously updated during the cascade, it acts like RESTRICT. This means that you cannot use self-referential ON UPDATE CASCADE operations. This is to prevent infinite loops resulting from cascaded updates.
Edit 2:
create table client
(
officeid char(6) not null,
clientno char(10) not null,
fname varchar(40) not null,
primary key (officeid, clientno)
);
create index officeid_clientno
on client (officeid, clientno);
create table compliance
(
officeid char(6) not null,
id smallint(5) unsigned not null,
clientid char(10) not null,
primary key (officeid, id),
constraint compliance_ibfk_2
foreign key (officeid, clientid) references client (officeid, clientno)
on update cascade
on delete cascade
);
create index officeid_clientid
on compliance (officeid, clientid, id);
create table task
(
officeid char(6) not null,
taskno char(10) not null,
clientid char(10) not null,
taskname varchar(50) not null,
complianceid smallint(5) unsigned null,
primary key (officeid, taskno),
constraint task_ibfk_1
foreign key (officeid, clientid) references client (officeid, clientno)
on update cascade,
constraint task_ibfk_4
foreign key (officeid, clientid, complianceid) references compliance (officeid, clientid, id)
on update cascade
);
create index officeid_clientid_complianceid
on task (officeid, clientid, complianceid);
FYI: I tried in mariadb 10.3 as well as mysql 8.0
The problem is related to the way relationships are declared.
First of all, as commented by #Nick, there is no need for a relation between task and client, as this is already covered by the relation to compliance. Commenting the declaration of this superfluous constraint is enough the make the error disappear, as you can see in this db fiddle.
create table task
(
officeid char(6) not null,
...
primary key (officeid, taskno),
-- constraint task_ibfk_1
-- foreign key (officeid, clientid) references client (officeid, clientno)
-- on update cascade,
constraint task_ibfk_4
foreign key (officeid, clientid, complianceid) references compliance (officeid, clientid, id)
on update cascade
);
Another suggestion is to use an autoincremented primary key in all tables (you can use an UNIQUE index to enforce composite referential integrity rules). This is the most usual way to proceed with MySQL, with which handling relationships is pretty straighforward.
I think that your problem stems from using mutable fields as primary keys
You can mitigate this by using a surrogate immutable primary key and adding a unique key to your mutable fields. You should be able to apply the same constraints as before without compromising data integrity
For example:
CREATE TABLE client (
id INT(10) UNSIGNED NOT NULL AUTO-INCREMENT PRIMARY,
officeid CHAR(6) NOT NULL,
clientno CHAR(10) NOT NULL,
fname VARCHAR(40) NOT NULL
);
CREATE UNIQUE INDEX uq-client-officeid-clientno IN client (officeid, clientno);
CREATE TABLE compliance (
id SMALLINT(5) UNSIGNED NOT NULL AUTO-INCREMENT PRIMARY,
client_id INT(10) UNSIGNED NOT NULL,
CONSTRAINT fk-compliance-client-id FOREIGN KEY id
REFERENCES client (id)
);
CREATE INDEX ix-compliance-id-client_id IN compliance (id, client_id);
CREATE TABLE task (
id INT(10) UNSIGNED NOT NULL AUTO-INCREMENT PRIMARY,
client_id INT(10) UNSIGNED NOT NULL,
compliance_id SMALLINT(5) UNSIGNED NULL,
taskno CHAR(10) NOT NULL,
taskname VARCHAR(50) NOT NULL,
CONSTRAINT fk-task-client-id FOREIGN KEY id
REFERENCES client (id),
CONSTRAINT fk-task-compliance-id-client_id FOREIGN KEY (compliance_id, client_id)
REFERENCES compliance (id, client_id)
);
This table structure mimics your current constraints and will allow you to update a clientno without needing the cascades
Note the foreign key fk-task-compliance-id-client_id which makes sure the compliance referenced by a task contains the correct client_id
I would also consider a separate table, office, with a surrogate integer primary key and containing the character based officeid. This could then be reference by the client table

Mysql composite key out of a foreign composite key

I'm trying to make a many-to-many relationship between two tables In Mysql WorkBench, and one of those 2 tables has a composite primary key ( parts are coming from 2 foreign keys). When I'm trying to generate the SQL I'm getting this error :
ERROR: Error 1215: Cannot add foreign key constraint
SQL Code:
-- -----------------------------------------------------
-- Table `A_D_schema`.`Resources_has_OwnerGroups`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `A_D_schema`.`Resources_has_OwnerGroups` (
`Resources_id` INT NOT NULL,
`OwnerGroups_id` INT NOT NULL,
`OwnerGroups_Instances_has_Customers_Instances_idInstances` INT NOT NULL,
`OwnerGroups_Instances_has_Customers_Customers_idCustomers` INT NOT NULL,
PRIMARY KEY (`Resources_id`, `OwnerGroups_id`, `OwnerGroups_Instances_has_Customers_Instances_idInstances`, `OwnerGroups_Instances_has_Customers_Customers_idCustomers`),
INDEX `fk_Resources_has_OwnerGroups_OwnerGroups1_idx` (`OwnerGroups_id` ASC, `OwnerGroups_Instances_has_Customers_Instances_idInstances` ASC, `OwnerGroups_Instances_has_Customers_Customers_idCustomers` ASC),
INDEX `fk_Resources_has_OwnerGroups_Resources1_idx` (`Resources_id` ASC),
CONSTRAINT `fk_Resources_has_OwnerGroups_Resources1`
FOREIGN KEY (`Resources_id`)
REFERENCES `A_D_schema`.`Resources` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
FOREIGN KEY (`OwnerGroups_id` , `OwnerGroups_Instances_has_Customers_Instances_idInstances` , `OwnerGroups_Instances_has_Customers_Customers_idCustomers`)
REFERENCES `A_D_schema`.`OwnerGroups` (`id` , `Instances_has_Customers_Instances_idInstances` , `Instances_has_Customers_Customers_idCustomers`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
From the SHOW ENGINE INNODB STATUS I can see this message :
Cannot resolve column name close to:
)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
FOREIGN KEY (`OwnerGroups_id` , `OwnerGroups_Instances_has_Customers_Instances_idInstances` , `OwnerGroups_Instances_has_Customers_Customers_idCustomers`)
REFERENCES `A_D_schema`.`OwnerGroups` (`id` , `Instances_has_Customers_Instances_idInstances` , `Instances_has_Customers_Customers_idCustomers`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
The SHOW CREATE TABLE Resources and SHOW CREATE TABLE OwnerGroups :
CREATE TABLE `Resources` (
`idResources` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(45) DEFAULT NULL,
`role` int(11) DEFAULT NULL COMMENT 'role : 1 disptcher \n0 admin',
PRIMARY KEY (`idResources`),
UNIQUE KEY `idresources_UNIQUE` (`idResources`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `OwnerGroups` (
`idOwnerGroups` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
`group` int(11) DEFAULT NULL,
PRIMARY KEY (`idOwnerGroups`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CONSTRAINT `fk_Resources_has_OwnerGroups_Resources1`
FOREIGN KEY (`Resources_id`)
REFERENCES `A_D_schema`.`Resources` (`id`)
Your Resources table doesn't have a column id. Its primary key is idResources.
CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
FOREIGN KEY (`OwnerGroups_id` , `OwnerGroups_Instances_has_Customers_Instances_idInstances` , `OwnerGroups_Instances_has_Customers_Customers_idCustomers`)
REFERENCES `A_D_schema`.`OwnerGroups` (`id` , `Instances_has_Customers_Instances_idInstances` , `Instances_has_Customers_Customers_idCustomers`)
Your OwnerGroups table doesn't have a column id. Its primary key is idOwnerGroups. It doesn't have the other two columns you reference at all.
In general, when you declare a foreign key, first you name the columns in the child table:
CREATE TABLE Child (
childCol1 INT,
childCol2 INT,
...
FOREIGN KEY (childCol1, childCol2) ...
Then you reference columns in the parent table:
... REFERENCES Parent (parentCol1, parentCol2)
);
You must use the names of columns as they exist in the parent table.
The columns you reference in the parent table must together be the PRIMARY KEY or UNIQUE KEY of that table. In other words, given the example above, it would not work against this Parent table:
CREATE TABLE Parent (
parentCol1 INT,
parentCol2 INT,
PRIMARY KEY (parentCol1)
);
Because the PRIMARY KEY does not include parentCol2.
In your case, the following should work:
CREATE TABLE IF NOT EXISTS `A_D_schema`.`Resources_has_OwnerGroups` (
`Resources_id` INT NOT NULL,
`OwnerGroups_id` INT NOT NULL,
`OwnerGroups_Instances_has_Customers_Instances_idInstances` INT NOT NULL,
`OwnerGroups_Instances_has_Customers_Customers_idCustomers` INT NOT NULL,
PRIMARY KEY (`Resources_id`, `OwnerGroups_id`, `OwnerGroups_Instances_has_Customers_Instances_idInstances`, `OwnerGroups_Instances_has_Customers_Customers_idCustomers`),
CONSTRAINT `fk_Resources_has_OwnerGroups_Resources1`
FOREIGN KEY (`Resources_id`)
REFERENCES `A_D_schema`.`Resources` (`idResources`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Resources_has_OwnerGroups_OwnerGroups1`
FOREIGN KEY (`OwnerGroups_id`)
REFERENCES `A_D_schema`.`OwnerGroups` (`idOwnerGroups`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
) ENGINE = InnoDB
I took out a couple of INDEX definitions that are redundant. You don't need to index your PRIMARY KEY, it's already the clustered index of the table. You don't need to index the column you use in a foreign key declaration, MySQL will index that column automatically if it need to (though if an index already exists for that column, the FK constraint will use that index).
I'm not sure I understand what your other two columns OwnerGroups_Instances_has_Customers_Instances_idInstances and OwnerGroups_Instances_has_Customers_Customers_idCustomers are meant to do. Typically in a many-to-many table, you only need enough columns to reference the primary keys of the respective parent tables.
Re your comment:
You should try refreshing the view of the schema from time to time. There's a button with a pair of curvy arrows, to the right of "SCHEMAS".

MySQL reference non-unique value in parent table

I have an approval tag and would like it to be populated down when it is changed in the parent table, however I cannot figure out how to reference the parent from the child to pull the value down.
For reference I want the value approval in reservations to be populated down to reservedTickets when I update the approval from 0 to 1 in reservations. However, to my understanding I cannot use a standard FOREIGN KEY or REFERENCE reference to reservations since approval is not unique.
Before anyone says anything about "why not have the value in only one table" it is to separate concerns between the administrator who has the ability to update the reservations table and a non-admin updating reservedTickets. Also, due to the high number of FOREIGN KEY constraints in reservedTickets having to join with the reservations table to track approval can be tricky depending on my starting point.
CREATE TABLE reservations(
rid int NOT NULL AUTO_INCREMENT,
aid int NOT NULL,
approval tinyint(1) NOT NULL,
creationTime TIMESTAMP
DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (rid),
FOREIGN KEY (aid) REFERENCES accounts (aid)
ON DELETE CASCADE
);
CREATE TABLE reservedTickets(
rid int NOT NULL,
tid int NOT NULL,
hid int NOT NULL,
approval tinyint(1) NOT NULL,
PRIMARY KEY (tid),
FOREIGN KEY (rid) REFERENCES reservations (rid)
ON DELETE CASCADE,
FOREIGN KEY (tid) REFERENCES tickets (tid)
ON DELETE CASCADE,
FOREIGN KEY (hid) REFERENCES people (hid)
ON DELETE CASCADE,
FOREIGN KEY (approval) REFERENCES reservations (approval)
ON UPDATE CASCADE
);
Personally I'd avoid cascade updates because of many locks the engine issues behind the scene, but if you really want it you can have a unique constraint on reservations(rid,approval) and foreign key in reservedTickets that references it. As far as I remember Mysql, it comes with a cost of extra index, but it gives you what you want.
On the other hand , you can implement desired functionality with trigger on reservation, or leave it up to application (or update table only through stored procedure that takes care of carrying this flag).
CREATE TABLE reservations(
rid int NOT NULL AUTO_INCREMENT,
aid int NOT NULL,
approval tinyint(1) NOT NULL,
creationTime TIMESTAMP
DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (rid),
CONSTRAINT UQ_RESERVATION_COMPOSITE UNIQUE(rid, approval),
...
);
CREATE TABLE reservedTickets(
rid int NOT NULL,
tid int NOT NULL,
hid int NOT NULL,
approval tinyint(1) NOT NULL,
PRIMARY KEY (tid),
FOREIGN KEY (rid,approval) REFERENCES reservations (rid,approval)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (tid) REFERENCES tickets (tid)
ON DELETE CASCADE,
FOREIGN KEY (hid) REFERENCES people (hid)
ON DELETE CASCADE , ....
);
It's not so much that you cannot use a foreign key on a non-unique column, because you can in InnoDB. However, the problem that arises with this would be if you have automatic updating or deleting on the foreign key, because the database would update all keys that were the same.
What you may be able to do, is use a prepared statement that allows you to update the approval column when updated from the reservations table, etc.