create table with #ManyToMany and #ManyToOne relation - java

I'm struggling with creating tables with #ManyToMany and #ManyToOne relations.
I have to create 3 tables, person, country, gender.
Person and country relationship #ManyToMany and person, gender #ManyToOne.
Is my code correct?
CREATE TABLE IF NOT EXISTS `di_person` (
`id_person` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(256) ,
`last_name` VARCHAR(256) ,
`additional_info` VARCHAR(256) ,
`gender_id` VARCHAR (50) UNIQUE REFERENCES di_gender,
`country_id` VARCHAR (50) UNIQUE REFERENCES di_country
) COLLATE='utf8_bin';
-- -----------------------------------------------------
-- Table 'gender`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `di_gender` (
id_gender INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
id_person INT,
name VARCHAR(50),
CONSTRAINT tb_fk FOREIGN KEY (id_person) REFERENCES di_person(id_person)
) COLLATE='utf8_bin';
-- -----------------------------------------------------
-- Table 'country`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `di_country` (
`id_country` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(256),
`id_person` VARCHAR (10) UNIQUE REFERENCES di_person
) COLLATE='utf8_bin';

I would have said not. Person is unique and should only have one entry per person. I suggest that the gender should remain in person and have a foreign key reference for validation purposes (i don't like enums), but am a bit dubious about holding country in the person table (more of this later). Gender should not have the person id and neither should country -otherwise duplicates of gender and country would exist. Not knowing what your data looks like i might create a person_country junction table so that a person can be associated with more than one country if that will never be the case then holding the country code in person (with a foreign key constraint) would be fine.

Related

How to cascade delete grand children table entities if they have a reference to foreign key of parent and primary key of grand parent

I have table relation like this scenario -> event -> plan and they are:
scenario_table:
CREATE TABLE `scenario` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`plan_cycle_id` bigint(20) unsigned NOT NULL,
`created_by` varchar(255) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `scenario_table_plan_cycle_id_fk` (`plan_cycle_id`),
CONSTRAINT `scenario_table_plan_cycle_id_fk` FOREIGN KEY (`plan_cycle_id`) REFERENCES `planning_cycle` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
event_table
CREATE TABLE `event` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`start_date` timestamp NULL DEFAULT NULL,
`end_date` timestamp NULL DEFAULT NULL,
`scenario_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_by` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_scenario_id` (`scenario_id`),
CONSTRAINT `fk_scenario_id` FOREIGN KEY (`scenario_id`) REFERENCES `scenario` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
plan_table
CREATE TABLE `plan` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`scenario_id` bigint(20) unsigned NOT NULL,
`input` json DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_by` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `plan_scenario_id` (`scenario_id`),
CONSTRAINT `FKnjhfw18pms9j2yhtvu954hcsi` FOREIGN KEY (`scenario_id`) REFERENCES `scenario` (`id`), // this was not there in create table command but later added by mysql //
CONSTRAINT `plan_scenario_id` FOREIGN KEY (`scenario_id`) REFERENCES `event` (`scenario_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
Now I want to cascade delete scenario, event and plan for some particular scenario_id. When there are no grandchildren, scenario and event are getting deleter as expected. But when a new entry is present in plan which refers a scenario_id, am getting this error while deletion:
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`db_dev`.`plan`, CONSTRAINT `plan_scenario_id` FOREIGN KEY (`scenario_id`) REFERENCES `event` (`scenario_id`))
I tried EAGER loading in eventEntity.java like this:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "scenario", cascade = CascadeType.ALL)
private List<planEntity> planEntityList;
and in planEntity.java like this:
#ManyToOne
#JoinColumn(name = "scenario_id", referencedColumnName = "id")
private ScenarioEntity scenario;
How I can handle this case through *entity.java files ?
In MySql when a table is InnoDB you can Add Foreign Key Constraints. Foreign Key checks is done when you update or delete a record. The results of foreign Key checks depend on the design of your table as you may allow cascading the update or delete or prevent the process of update or delete.
The following is an example of a parent:
CREATE TABLE parent (
id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
Example of child table that allows parent table to delete or update the (id) field of the parent table (Child also will be deleted):
CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB;
Example of child table that prevents the update of (id) field of parent but allows parent table to be deleted. (Child also will be deleted):
CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE
) ENGINE=INNODB;
Example of child table that prevents parent table to delete or update the (id) field of the parent table. This will give error like "Cannot Delete or Update a Parent Row: A Foreign Key Constraint Fails":
CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
) ENGINE=INNODB;
You have four options when using foreign key constraints :
RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
RESTRICT : is the default if you don't include ON UPDATE/ON DELETE
CASCADE : Delete child when delete parent or update parent_id when id of parent changed.
for more information you can see FOREIGN KEY Constraints
There is also a variable that control foreign key checks. If you set it to 0 (false) you will disable foreign key checks.
SET FOREIGN_KEY_CHECKS=0;
Back to your database, I think it is better to modify your tables structure to allow cascade delete. You can also use ON DELETE SET NULL then later you can delete any record where parent_id=null. If you can't modify tables structure then you have to first delete records in child table before deleting parent record.

MySQL Get value inserted by trigger in Java

Using MySQL, I have the following SQL Table definition:
CREATE TABLE books (
author INT,
book INT,
name VARCHAR(128),
PRIMARY KEY(author, book)
);
What I want is that I have an Id for author that I set manually and an Id for book that is incremented for each author id. Therefore I created a trigger like so:
CREATE TRIGGER trBooks
BEFORE INSERT ON books
FOR EACH ROW SET NEW.book = (
SELECT COALESCE(MAX(book), -1) + 1 FROM books
WHERE author = NEW.author
);
This works fine for me. But now I need to know the book id that was set for my inserted entry that I inserted in Java. Something like the Insert with Output as in MSSQL or a Statement.executeQuery("INSERT ..."). The solution has to be thread safe, so a separate INSERT and SELECT is no good solution, since there might have been another INSERT in the meantime.
Thanks for your help!
Your data model just doesn't make sense. You have two entities, "books" and "authors". These should each be represented as a table. Because a book can have multiple authors and an author can write multiple books, you want a junction table.
This looks like this:
CREATE TABLE Books (
BookId INT auto_increment primary key,
Title VARCHAR(255)
);
CREATE TABLE Authors (
AuthorId INT auto_increment primary key,
Name VARCHAR(255)
);
CREATE TABLE BookAuthors (
BookAuthorId INT auto_increment primary key,
AuthorId INT,
BookId INT,
CONSTRAINT fk_BookAuthor_BookId FOREIGN KEY (BookId) REFERENCES Books(BookId),
CONSTRAINT fk_BookAuthor_AuthorId FOREIGN KEY (BookId) REFERENCES Authors(AuthorId),
UNIQUE (AuthorId, BookId)
);
As for your question about inserts. You don't need a trigger to set auto-incremented ids. You can use LAST_INSERT_ID() to fetch the most recent inserted value.

H2 database: referring to a table in root schema from a foreign key constraint

Given a table in root schema:
CREATE TABLE user (
username VARCHAR(50),
password VARCHAR(50));
and a table in Quiz schema:
CREATE TABLE Quiz.Results (
username VARCHAR(50),
points INT,
FOREIGN KEY (username) REFERENCES user(username));
I'm unable to actually create the foreign key, because the database claims the table user does not actually exist. Neither can I subsequently add the foreign key:
ALTER TABLE QUIZ.RESULTS
ADD FOREIGN KEY (username) REFERENCES user (username)
Both tables are, of course, stored in the same database.
Since this is just a piece of homework, I'm more than happy to simply skip adding a foreign key. But I'm curious if this is indeed a limitation in H2, a bug, or if it works as intended.
Can I somehow refer to table user outside the quiz schema?
You would need to explicitly set the schema name if you refer to a table in a different schema. The default schema name for H2 is public. Example:
CREATE TABLE user (
username VARCHAR(50),
password VARCHAR(50));
create schema quiz;
CREATE TABLE Quiz.Results (
username VARCHAR(50),
points INT,
FOREIGN KEY (username)
REFERENCES public.user(username));
To create the foreign key constraint later, use:
ALTER TABLE QUIZ.RESULTS
ADD FOREIGN KEY (username)
REFERENCES public.user(username) ;
yes very much possible. You need to use corresponding Schema name for both tables.
suppose your defualt schema name is DefaultSchema then your query will be
ALTER TABLE QUIZ.RESULTS
ADD FOREIGN KEY (username) REFERENCES DefaultSchema.user (username)

What is the primary key of an audit table managed by Hibernate Envers?

I am using Hibernate Envers to audit some entities. I manually created the associated audit tables. However, I am having trouble determining what an audit table's primary key should be. For example, consider a fictional table designed to store customers:
CREATE TABLE CUSTOMER
(
CUSTOMER_ID INTEGER,
CUSTOMER_NAME VARCHAR(100),
PRIMARY KEY (CUSTOMER_ID)
)
And you create the audit table:
CREATE TABLE CUSTOMER_REVISION
(
REVISION_ID INTEGER,
REVISION_TYPE_ID INTEGER,
CUSTOMER_ID INTEGER,
CUSTOMER_NAME VARCHAR(100),
PRIMARY KEY (???)
)
Here were the options I considered:
Primary key: REVISION_ID
This cannot be the primary key because multiple entities of the same class may be modified during the same revision.
Primary key: (REVISION_ID, CUSTOMER_ID)
This seems more likely, but I'm not sure if Envers will insert multiple records per customer per revision.
Primary key: (REVISION_ID, REVISION_TYPE_ID, CUSTOMER_ID)
This seems like overkill, but it may be possible that Envers will insert different types of records (add, modify or delete) per customer per revision.
Primary key: A new column
Perhaps the primary key must simply be another column containing a synthetic primary key.
What is the true primary key of an audit table managed by Hibernate Envers?
Judging by the examples in the documentation, it appears that the primary key in my example would be (REVISION_ID, CUSTOMER_ID). Here is the example in the documentation:
create table Address (
id integer generated by default as identity (start with 1),
flatNumber integer,
houseNumber integer,
streetName varchar(255),
primary key (id)
);
create table Address_AUD (
id integer not null,
REV integer not null,
flatNumber integer,
houseNumber integer,
streetName varchar(255),
REVTYPE tinyint,
***primary key (id, REV)***
);
The primary key of audit table is the combination of original id(id) and revision number(rev) of the audit table.
As the official documentation there can be at most one historic entry for a given entity instance at a given revision, which simply means unique combination of above two column.

My Insert Into Statement is not working

I was working with UIs where the user will click the add button to add employees, but when I do it, it gives me an error like this
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`finalpayroll`.`personal_info`, CONSTRAINT `personal_info_ibfk_1`
How would I fix this?? I know I am using a parent key, and its foreign key is the User, and also take note that the parent key has already a data, but it seems my query won't work, why is that? I am using a foreign key with delete cascade and on update cascade so that when I delete a data, all of the child table rows will be deleted, vice versa. here's my key for adding or inserting statements
public void addEmployee(Personal p ,Contact c,Employee e) {
Connection conn = Jdbc.dbConn();
Statement statement = null;
String insert1 = "INSERT INTO personal_info (`First_Name`, `Middle_Initial`, `Last_Name`, `Date_Of_Birth`, `Marital_Status`, `Beneficiaries`) VALUES ('"+p.getFirstName()+"', '"+p.getMiddleInitial()+"'" +
" , '"+p.getLastName()+"', '"+p.getDateOfBirth()+"', '"+p.getMaritalStatus()+"', '"+p.getBeneficiaries()+"')";
try {
statement = conn.createStatement();
statement.executeUpdate(insert1);
statement.close();
conn.close();
JOptionPane.showMessageDialog(null, "Employee Added!!");
} catch(Exception ex) {
ex.printStackTrace();
}
}
Users table:
CREATE TABLE `users` (
`idusers` int(11) NOT NULL AUTO_INCREMENT,
`emp_id` varchar(45) DEFAULT NULL,
`emp_pass` varchar(45) DEFAULT NULL,
PRIMARY KEY (`idusers`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
Personal_info table:
CREATE TABLE `personal_info` (
`idpersonal_info` int(11) NOT NULL AUTO_INCREMENT,
`First_Name` varchar(45) DEFAULT NULL,
`Middle_Initial` varchar(45) DEFAULT NULL,
`Last_Name` varchar(45) DEFAULT NULL,
`Date_Of_Birth` varchar(45) DEFAULT NULL,
`Marital_Status` varchar(45) DEFAULT NULL,
`Beneficiaries` varchar(45) DEFAULT NULL,
PRIMARY KEY (`idpersonal_info`),
CONSTRAINT `personal_info_ibfk_1`
FOREIGN KEY (`idpersonal_info`)
REFERENCES `users` (`idusers`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
You are trying to insert a record with 6 fields: First_Name, Middle_Initial, Last_Name, Date_Of_Birth, Marital_Status and Beneficiaries. Your schema is currently unknown but none of these fields seem to be a candidate foreign key to id of User table you mentioned. Thus I think there is a default value for that foreign key column and that default value is missing in User table.
Needless to say, you shouldn't have a default value for a foreign key of any table..
I am adding these information regarding your questions in comments and update on your question:
A foreign key is a link between a child table and parent table, personal_info and users tables in your case respectively. Child table's foreign key column must reference to a key value in parent table which means that for every value in child table's FK column, there must be a value in parent table's linked column.
Now, in your case when you try to insert a new personal_info record MySQL assigns a idpersonal_info to it, since you defined it as auto increment. But since there is a link to users table, MySQL searchs for the new idpersonal_info to be inserted in users table's idusers column. And as you are getting this exception, you surely don't have that value in the users table.
You can change your table structure as follows:
CREATE TABLE `personal_info` (
`idpersonal_info` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
... OTHER FIELD DEFINITIONS,
PRIMARY KEY (`idpersonal_info`),
CONSTRAINT `user_id_fk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`idusers`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
And your query will need to include user_id field as well. So it will be something like this:
INSERT INTO personal_info
(`user_id`, `First_Name`, `Middle_Initial`, `Last_Name`, `Date_Of_Birth`, `Marital_Status`, `Beneficiaries`)
VALUES ( .... SET YOUR VALUES HERE. DON'T FORGET TO SET A VALID USER_ID
Looks like in your Personal_Info table you have a column called "finalpayroll", that points to a column in another table (a foreign key) and it's required (not nullable). In your insert you're not giving it a value. So what you could do is make that column nullable.
Or could be the other way around as #Konstantin Naryshkin is saying
What the error means is that you are trying to insert a value into a column with a foreign key a value that is not in the remote table.
I assume that there is a user column that we are not seeing. Since you are not explicitly setting the value, I assume that it is getting a default. The default value is not in the parent table.

Categories