Inserting into multiple tables at once - mysql

Structure:
Table A)
CREATE TABLE Item (
Id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id of an item',
`By` VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (Id),
CONSTRAINT FK_Item_User_Name FOREIGN KEY (`By`)
REFERENCES User(Name) ON DELETE NO ACTION ON UPDATE CASCADE
)
Table B)
CREATE TABLE ItemName (
Item_Id INT(11) UNSIGNED NOT NULL COMMENT 'Item id this name is referencing',
Language VARCHAR(5) NOT NULL COMMENT 'language code by ISO 639-2/T',
Translation VARCHAR(50) NOT NULL COMMENT 'Item name for given language',
PRIMARY KEY (Item_Id, Language),
CONSTRAINT FK_ItemName_Item_Id FOREIGN KEY (Item_Id)
REFERENCES Item(Id) ON DELETE CASCADE ON UPDATE CASCADE
)
Table C)
CREATE TABLE User (
Name VARCHAR(50) NOT NULL,
Password VARCHAR(50) NOT NULL,
Salt VARCHAR(255) NOT NULL,
Blocked TINYINT(1) DEFAULT 0,
PRIMARY KEY (Name),
UNIQUE INDEX UK_User_Name (Name)
)
Question:
Now I want to insert a new item. Let's say the user provides us with:
Translation
Language code
Username
What i got so far:
I was thinking of puting it in a transaction and inserting into each table after eachother. But then i'm stuck on how do i know what Item.Id to use in the ItemName.Item_Id field since the Item table will AI a new Id for the insert.
I could get the last Item.Id, but then it might be pointing to another item if multiple users were to be inserting a new item simulaneuosly.
ps. Engine=InnoDB

BEGIN;
INSERT into one table;
get the last_insert_id() -- there are many ways to do this, depending on the API
INSERT into next table...
... ;
COMMIT;
Do the inserts in the order that avoids violating your FOREIGN KEYs.

Related

Could a foreign key column has multivalue in one row from the same reference table?

I'm trying to create a database on MySQL Workbench. Is it legal if a foreign key column has a multivalue in one row? I want to do that because based on the event category the user would be allowed to see the event or not. Also, there could be multiple event categories for one event. I know that I can make a composite key to event table. But I'm wondering that can I have multivalue as a foreign key in one row?
Here is my Event table:
CREATE TABLE IF NOT EXISTS `mydb`.`EVENT` (
`eventID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`eventCategory` INT UNSIGNED NOT NULL,
`name` VARCHAR(45) NOT NULL,
`eventDescription` VARCHAR(280) NULL,
`date` DATETIME(1) NOT NULL,
`locationDescription` VARCHAR(45) NOT NULL,
`regionID` INT UNSIGNED NOT NULL,
PRIMARY KEY (`eventID`),
INDEX `fk_EVENT_category_1_idx` (`eventCategory` ASC) VISIBLE,
INDEX `fk_EVENT_region_1_idx` (`regionID` ASC) VISIBLE,
CONSTRAINT `fk_EVENT_region_1`
FOREIGN KEY (`regionID`)
REFERENCES `mydb`.`REGION` (`regionID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_EVENT_category_1`
FOREIGN KEY (`eventCategory`)
REFERENCES `mydb`.`CATEGORY` (`categoryID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
And I want to store multiple categories in one ro. I want to do that because based on those categories, some of the users wouldn't be allowed to see the event in the application.
Here is my category table:
CREATE TABLE IF NOT EXISTS `mydb`.`CATEGORY` (
`categoryID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`disorderID` INT UNSIGNED NOT NULL,
`categoryDescription` VARCHAR(45) NOT NULL,
PRIMARY KEY (`categoryID`, `disorderID`),
INDEX `fk_CATEGORY_disorder_1_idx` (`disorderID` ASC) VISIBLE,
CONSTRAINT `fk_CATEGORY_disorder_1`
FOREIGN KEY (`disorderID`)
REFERENCES `mydb`.`DISORDERS` (`disorderID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
And I want to store multiple categories in one ro. I want to do that because based on those categories, some of the users wouldn't be allowed to see the event in the application.
No. Don't got that way. This would denormalize your schema and make simple things utterly complex later on.
You have a many-to-many relationship between event and categories. The proper way to represent that is to create a third table, where each event/category table is stored on a separate row.
Something like:
create table event_categories (
event_id int not null,
category_id int not null,
primary key (event_id, category_id),
foreign key(event_id) references event(event_id),
foreign key(category_id) references category(category_id),
);

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.

Foregin keys returns empty results

I'm using an a mySQL db on localhosts. Created table with primary key and another table with foreign key pointing to that one, but when I want to see the results all I geted is "alert" that MySQL returned emty result. Here my tables
CREATE TABLE example_1(
ex1_id int NOT NULL AUTO_INCREMENT,
first_name varchar(50) NULL,
last_name varchar(50) NULL,
CONSTRAINT example_1_pk PRIMARY KEY (ex1_id)
);
CREATE TABLE example_2 (
ex2_id int NOT NULL AUTO_INCREMENT,
acces_lvl int NOT NULL,
CONSTRAINT example_2_pk PRIMARY KEY (ex2_id)
);
CREATE TABLE example_3 (
ex3_id int NOT NULL AUTO_INCREMENT,
first int NOT NULL,
second int NOT NULL,
CONSTRAINT example_3_pk PRIMARY KEY (ex3_id),
FOREIGN KEY (first) REFERENCES example_1(ex1_id),
FOREIGN KEY (second) REFERENCES example_2(ex2_id)
);
Then I add something to db, eg.
INSERT INTO `example_1`(`first_name`, `last_name`) VALUES ('foo', 'bar');
and
INSERT INTO `example_2`(`acces_lvl`) VALUES (2)
then when I try
SELECT * FROM `example_3`
I have nothing, empty results. Shouldn't be there id's from other tables? Am I doing something wrong, or I didn't do something? I'm totally noob in database.
Because you did not insert any data into example_3. Foreign key constraints don't propagate data, they just enforce the data relationship, so when you do insert data into example_3, the values you put in the columns with foreign key constraints have corresponding values in other table.

How can I do an insert into to a column when I have a foreign key in mysql

Hello guys I have some problems I have been trying to inser data to a column which have a foreign key in MSQL But I can't make it work. I would appreciate if somebody help me with this.
Category
(
idCategory int(20) auto_increment not null,
NameCategory varchar(40) not null,
PRIMARY KEY (idCategory)
);
SubCategory
(
idSubCategory int(10)not null primary key auto_increment ,
NameSub varchar(40) not null,
FK_Category int not null
);
ALTER TABLE SubCategory auto_increment=1;
ALTER TABLE SubCategory
ADD FOREIGN KEY (PK_Category)
REFERENCES Category (idCategory);
I have tried this 3 ways but nothing works
INSERT INTO Subcategory (NameSub)
VALUES ( 'Nisan');
INSERT INTO Subcategory (idSubCategory, NameSub,PK_Category)
VALUES (01, 'Nisan', 01);
INSERT INTO subcategory (NameSub, PK_Category) VALUES
( 'Nisan' SELECT idCategory from Category WHERE idCategory = 1 );
For some reason your Foreign key constrains script didn't work for me so I did it another an alternate way.
I worked out why afterwards, you reference you have ADD FOREIGN KEY (PK_Category) rather than (FK_Category)
CREATE TABLE Category
(
idCategory int(20) auto_increment not null,
NameCategory varchar(40) not null,
PRIMARY KEY (idCategory)
);
CREATE TABLE SubCategory
(
idSubCategory int(10)not null primary key auto_increment ,
NameSub varchar(40) not null,
FK_Category int not null,
INDEX IDX_Category(FK_Category),
FOREIGN KEY (FK_Category)
REFERENCES Category(idCategory)
ON DELETE CASCADE
);
ALTER TABLE SubCategory auto_increment=1;
And here are the inserts
INSERT INTO Category (NameCategory)
VALUES ('Car');
INSERT INTO Subcategory (NameSub,FK_Category)
VALUES ('Nisan', 01);
As you didn't specify the contents of the table of Category I've created one.
Note: The issue you may be having is that your parent table is empty, and then it would error.
SQL Fiddle

Cannot INSERT because of Foreign key constraints - mysql

So I don't understand why I cannot insert data in my table that have foreign constraint keys or even modify anything in it.
Here is an example of the tables that are created. I am trying to insert data in the addresses table:
///////////////////////ADDRESSES TABLE ////////////////////////
CREATE TABLE IF NOT EXISTS addresses (
id INT NOT NULL AUTO_INCREMENT,
addressline1 VARCHAR(255) NOT NULL,
addressline2 VARCHAR(255) NOT NULL,
postcode VARCHAR(255) NOT NULL,
phonenumber INT(13) NOT NULL,
country_id INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (country_id) REFERENCES countries(id)
ON UPDATE CASCADE
ON DELETE RESTRICT
) ENGINE=InnoDB ";
///////////////////////COUNTRIES TABLE ////////////////////////
CREATE TABLE IF NOT EXISTS countries (
id INT NOT NULL AUTO_INCREMENT,
countryname VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
)
The issue here is that you are trying to insert into a referencing table (addresses) when the referenced entry (the country you reference) does not exist. That's what's triggering the FOREIGN KEY CONSTRAINT exception.
Try first inserting some countries into the countries table, then inserting some addresses where you reference those countries you entered in the first step.
As for your second question, that's a choice for you to make. I would probably choose to have the User have an Address (address field in the User table), but some of that depends on how the data is being used/updated.
Have a quick look through this resource if you're new to relational database design. It covers (in brief) topics like relationship types, key constraints, and normal forms.